shadcn.io is not affiliated with official shadcn/ui
Terminal Text plays a short terminal session: a prompt, a command typed a character at a time, its output printed a line at a time, then the next command, ending on a prompt with a blinking caret. You write the session as you'd paste it into a README: lines that start with $ are commands, anything else is output, and lines that start with a tick, a cross, a warning sign or a tag such as [info] take the theme's colours.
Use it for an install step on a landing page, a CLI's hero, or a quick-start that shows what running a command looks like. For a single typed line inside your own mock-up, use Typing Text; for a stream of log lines that never ends, Log Stream Text. There's no timer: every character and line is in place from the start, hidden, and a CSS keyframe animation the install adds to your stylesheet shows each at its moment, so the box never changes size and nothing re-renders. With reduced motion the whole session is there at once.
Installation
Usage
import { TerminalText } from "@/components/ui/terminal-text";<TerminalText
text={`$ npx shadcn@latest add terminal-text
✓ Created components/ui/terminal-text.tsx`}
/>Demos
Session
Several commands in a row, each with its output. prompt is what shows before each command, a path or a host as your shell prints it; the commands in text still start with $ . Output that starts with warning or error takes the theme's warning or destructive colour.
Timing
delay is the wait at each prompt before its command is typed, and again before its output, speed the average time per character, and stagger the time between one line of output and the next. cursor is the caret's shape: block, the default, bar, underscore or none.
Accessibility
Screen readers read the whole session once, line by line, from a visually hidden copy, never the half-typed commands; the animated session is hidden from them. The prompts can't be selected, so a command copied from the box pastes without its $. The session stays left to right on a right-to-left page, as a terminal does. The caret blinks once a second, only while it waits, and with reduced motion the session is all there, with a still caret on the last prompt.
FAQ
How do I write the session?
As one string, a line per line, the way a README shows a terminal: a line that starts with $ (or is just $) is a command, typed after the prompt; every other line is output, printed whole. Blank lines at the start and the end are dropped, so a template literal can start on its own line.
Which output lines are coloured?
Lines that start with ✓ or [ok] take the theme's success colour, ✗, [error] or error the destructive colour, ⚠, [warn] or warning the warning colour, and ℹ or [info] the info colour; the rest are muted. Each output line has data-tone, so you can style them from outside.
When does it play?
Once, when at least a quarter of it is in view. Pass trigger="mount" to play it as soon as the page shows it, from CSS alone, before the page's script loads.
API Reference
TerminalText
<div> data-slot="terminal-text"
textstring
The session, a line per line: a line that starts with $ is a
command, typed after the prompt; any other line is output, printed
whole.
cursor?"block" | "bar" | "underscore" | "none"
The caret: a terminal's block, a bar, an underscore, or none. @default "block".
- Type
"block" | "bar" | "underscore" | "none"- Default
"block"
delay?number
The wait at each prompt before its command is typed, and after a command before its output prints, in milliseconds.
- Default
500
prompt?string
What's shown before each command. @default "$".
- Default
"$"
speed?number
The time to type one character of a command, on average, in milliseconds. @default 50.
- Default
50
stagger?number
The time between one line of output and the next, in milliseconds. @default 100.
- Default
100
trigger?"mount" | "view"
When it plays: as soon as it's on the page, or once it scrolls into view.
- Type
"mount" | "view"- Default
"view"
render?ReactElement | ((props: object, state: object) => ReactElement)
Replace the host element or compose it with another component.
- Type
ReactElement | ((props: object, state: object) => ReactElement)
className?string
Merged with the part's classes.
data-tone?string
Mirrors tone.
data-view?string
"in" when visible is true, otherwise "out".
Related
- Pro
Typing Text
EntranceOne typed line in your own mock-up
- Pro
Log Stream Text
MotionA stream of log lines that never ends
- Pro
JSON Text
EntranceA response written out key by key
- Pro
Syntax Text
EntranceA code sample, token by token
- Pro
Copy Text
InteractiveLet people copy the install command
- Pro
Backspace Text
CyclingA command edited before it runs