Terminal React component for Tailwind CSS v4
v1.0.0Added in 1.14.0
An animated React terminal window for dev-tool landing pages and docs: typed commands, output, spinners and progress bars.
Scroll the window into view and it plays a session: a caret types each command after the prompt, a spinner turns into a check or a progress bar fills to 100%, then the output prints line by line and the prompt waits with a blinking caret. The whole transcript is laid out from the first frame, so the page never shifts, and screen readers and search engines get the full text. The copy button copies every command at once and the replay button starts over. Long lines scroll sideways inside the window only (Tab to it and use the arrow keys); the page never scrolls sideways, and below 640px the type steps down one size. With reduced motion on, the finished transcript shows at once.
Terminal is a Pro React component in the React effect components category, written in TypeScript for React 19 and Tailwind CSS v4. It installs as source with npx wingo-ui@latest add terminal, together with Button, Copy Button, Tooltip, useControllableState, Motion presets and 2 more and the npm packages motion and lucide-react.
Add to a project
Requirements: React 19 and Tailwind CSS v4, in Next.js (App Router or Pages), Vite or React Router. Installation guide · Next.js setup · Vite setup
npx wingo-ui@latest add terminalTerminal is part of Pro, with 298 more Pro items: $8 a month or $150 once. 14-day refund before you download any Pro item. See plans
Usage
Import Terminal from @/components/ui/terminal.
import { Terminal, type TerminalLine } from "@/components/ui/terminal"
const lines: TerminalLine[] = [
{ command: "npm install @acme/sdk", spinner: "Installing", duration: 1200, output: [{ text: "✓ Added 1 package in 1.8s", tone: "success" }] },
{ command: "npx acme login", output: ["Opening https://acme.dev/login in your browser", { text: "✓ Signed in as emma@northwind.com", tone: "success" }] },
{ command: "npx acme deploy", progress: "Uploading", duration: 1600, output: [{ text: "✓ Live at https://northwind.acme.app", tone: "success" }] },
]
export function InstallSteps() {
return <Terminal lines={lines} title="emma@macbook: ~/northwind" mode="dark" trafficLights className="max-w-xl" />
}Props
linesTerminalLine[]The session, one step per entry: { command?, output?, delay?, tone?, spinner?, progress?, duration?, prompt? }. A step types its command, runs its spinner or progress bar for duration ms, then prints its output lines (strings or { text, tone }). Defaults to a short install, build and deploy session (DEFAULT_TERMINAL_LINES).
titledefault""stringThe window title, like a path or a host. Centered with the mac chrome, left-aligned with plain. Also names the transcript region for screen readers.
promptdefault"$"stringThe prompt before every command, painted in the tone. A step can set its own ("#", "~/app ❯").
copyValuedefault""stringThe text the copy button copies. Defaults to every command, one per line.
labelsPartial<TerminalLabels>Every string: { region: "Terminal", copy: "Copy commands", copied: "Copied", replay: "Replay" }. region names the transcript when there is no title.
chromedefault"mac""mac" | "plain" | "none"mac: three window dots and a centered title. plain: a title bar with the title on the left. none: only the transcript, with the buttons floating in the corner.
trafficLightsdefaultfalsebooleanColors the mac dots red, yellow and green instead of a calm gray. Override them with [--terminal-dot-1:...] up to 3.
modedefault"auto""auto" | "dark"auto follows the page theme; dark keeps the window dark on a light page, the classic look for a hero.
sizedefault"md""sm" | "md" | "lg"Type 12 / 13 / 14px (one step smaller below 640px), with matching padding and title bar height (36 / 40 / 48px).
radiusdefault"md""none" | "sm" | "md" | "lg" | "full"Corner radius of the window: 0, 12, 16 or 24px; full falls back to 24px.
tonedefault"neutral""neutral" | "brand" | "success" | "warning" | "danger" | "info"Color of the prompt, the caret and the progress bars. Output colors come from each step's tone.
colordefault""stringAny CSS color for the prompt, caret and progress bars. Replaces the tone; leave empty to use the tone.
showCopydefaulttruebooleanA copy button in the title bar that copies the commands, with a check and a screen reader announcement.
showReplaydefaulttruebooleanA replay button that plays the session again from the start. Hidden when animate is off.
cursordefaulttruebooleanThe block caret that types each command, and the waiting prompt with a blinking caret at the end.
speeddefault45numberMilliseconds per typed character.
triggerdefault"in-view""mount" | "in-view"mount plays as soon as the page has loaded; in-view waits until a third of the window is on screen.
loopdefaultfalsebooleanStarts over after the last line. A looping window rests while it is off screen.
loopDelaydefault2400numberWith loop, how long the finished transcript stays before it starts over, in ms.
animatedefaulttruebooleanOff renders the finished transcript with no typing, like a static code sample.
defaultPlayingdefaulttruebooleanWhether it plays on its own once triggered. Off waits on an empty prompt until playing turns true or replay is pressed.
playingbooleanControlled playback: true plays (from the start once it has finished), false pauses where it is. Pair it with onPlayingChange, which reports false when the session ends.
onPlayingChange(playing: boolean) => voidCalled when playback starts or stops, including false at the end of a session that does not loop.
onComplete() => voidCalled each time the session finishes (every round with loop).
refRef<HTMLDivElement> (a useRef object or an (el) => void callback)The window element.
classNamesPartial<Record<"header" | "dots" | "title" | "actions" | "viewport" | "body" | "line" | "prompt" | "command" | "caret" | "output" | "spinner" | "progress", string>>Extra classes for the inner parts.
classNamestringExtra classes for the window, merged last. Set a width or override the tone vars here.
Parts
TerminalLine
typeOne step of the session: command, output (TerminalOutput or an array), delay (ms before it starts), tone, spinner or progress (a label), duration (ms they run, default 1400) and prompt.
TerminalOutput
typeAn output line: a string, or { text, tone } to color one line on its own.
TerminalTone
typeThe line colors: the six tones plus "muted", the default dimmed output.
TerminalLabels
typeThe strings of labels: region, copy, copied and replay.
DEFAULT_TERMINAL_LABELS
constantThe English labels, to spread and translate.
DEFAULT_TERMINAL_LINES
constantThe sample install, build and deploy session shown when lines is left out.
TerminalSize
type"sm" | "md" | "lg".
TerminalRadius
type"none" | "sm" | "md" | "lg" | "full".
TerminalChrome
type"mac" | "plain" | "none".
TerminalTrigger
type"mount" | "in-view".
TerminalMode
type"auto" | "dark".
TerminalState
typeThe playback state, written to the root as data-state: "idle", "playing" or "done".
TerminalSlot
typeThe keys of classNames.
TerminalProps
typeThe props of Terminal, plus every div attribute.
Examples
A failing test run
A danger spinner ends in a cross; output lines take their own success, warning and danger tones.
Sizes
12, 13 and 14px type with matching padding and title bar, one step smaller on phones.
Window chrome
mac dots with traffic lights, a plain title bar, or no chrome with floating buttons.
Controlled playback
playing and onPlayingChange drive it from your own button; onComplete counts each run.
Looping hero
A dark window with a brand prompt that replays while it stays on screen.
Long commands on a phone
Lines never wrap: the window scrolls sideways inside itself and the page stays put.
Custom color
Any CSS color for the prompt, caret and bars, and a per-step prompt like a root shell.
Files
- components/ui/terminal.tsx
FAQ
Is the React Terminal component free?
The preview, props and docs are free; copying the source needs a Pro plan. See plans.
How do I install Terminal?
Run npx wingo-ui@latest add terminal. It also adds the Wingo UI items it builds on (Button, Copy Button, Tooltip, useControllableState, Motion presets and 2 more) and the npm packages motion and lucide-react. With shadcn, add the @wingo-ui registry with your API key, then run npx shadcn@latest add @wingo-ui/terminal.
See also
More React effect components
Articles using this component
- React Terminal Component: Typing Animation Without Jank
Component guides8 min read