A command-line style panel that types its lines in once: a prompt, the commands, then the output. It has a copy button, and a still mode that shows every line at once. The lines are real text in the page from the start.
Optional, and kept apart.
Nothing here is included in a project unless you add it, and the plain component it builds on is unchanged. This effect is decoration: it is hidden from screen readers, stands still for visitors who prefer reduced motion, and can be paused. Use Still on a preview to see that version.
npx rdloom initCreated rdloom.jsonnpx rdloom add buttonAdded button to src/components/ui
import { Terminal } from "@rdloom/react";
export default function TerminalBasicExample() {
return (
<div className="flex w-full justify-center">
<Terminal
className="w-full max-w-2xl"
lines={[
{ text: "npx rdloom init" },
{ text: "Created rdloom.json", kind: "output" },
{ text: "npx rdloom add button" },
{ text: "Added button to src/components/ui", kind: "output" },
]}
/>
</div>
);
}Installation
npx rdloom add terminalCopies the source into src/components/rdloom. Edit it freely: rdloom upgrade merges later versions into your changes. It needs react-aria-components; add --install to install them.
It also adds rdloom-motion.css next to your tokens and imports it from the tokens file, once: no setup, and no inline styles. The plain components you already use are untouched.
Use another registry client
npx shadcn@latest add https://rdloom.vimalbhatt.com/r/terminal.jsonWorks, but without upgrade tracking, and you import the motion CSS yourself.
Usage
import { Terminal } from "@rdloom/react";
<div className="flex w-full justify-center">
<Terminal
className="w-full max-w-2xl"
lines={[
{ text: "npx rdloom init" },
{ text: "Created rdloom.json", kind: "output" },
{ text: "npx rdloom add button" },
{ text: "Added button to src/components/ui", kind: "output" },
]}
/>
</div>Install
npm install @rdloom/reactnpx rdloom add dialog
import { Terminal } from "@rdloom/react";
export default function TerminalInstallExample() {
return (
<div className="flex w-full justify-center">
<Terminal
className="w-full max-w-2xl"
label="Install steps"
prompt=">"
speed={25}
copyLabel="Copy commands"
lines={[{ text: "npm install @rdloom/react" }, { text: "npx rdloom add dialog" }]}
/>
</div>
);
}Still
npm run buildBuilt 42 pages in 6.1sNo problems found
import { Terminal } from "@rdloom/react";
export default function TerminalStillExample() {
return (
<div className="flex w-full justify-center">
<Terminal
isPaused
className="w-full max-w-2xl"
label="Build output"
lines={[
{ text: "npm run build" },
{ text: "Built 42 pages in 6.1s", kind: "output" },
{ text: "No problems found", kind: "output" },
]}
/>
</div>
);
}API Reference
Defined by the spec. Components also accept the props of the React Aria component they wrap.
| Prop | Type | Default |
|---|---|---|
linesrequiredThe lines, each { text, kind }. kind is "command" (typed, with a prompt) or "output" (appears whole after a short pause). Default kind is command. | { text: string; kind?: "command" | "output" }[] | none |
labelAccessible name of the panel. | string | "Terminal" |
promptText shown before each command. | string | "$" |
speedMilliseconds per typed character. | number | 35 |
lineDelayMilliseconds to wait between lines. | number | 450 |
showCopyShows a Copy button that copies the commands (without prompts or output). | boolean | true |
copyLabelText of the button. | string | "Copy" |
copiedLabelText of the button after copying. | string | "Copied" |
isPausedStill mode: shows every line at once and does not type. | boolean | false |
Accessibility
Role group, WCAG 2.2 AA. Tested with axe and keyboard tests; screen reader checks are in the audit checklist.
Keyboard
- Tab: moves to the Copy button and to the scrollable text area
- Enter or Space: copies the commands
Screen readers announce
- Group named by label, then the lines as plain text, then the Copy button
What your code must do
- The panel is a group named by label
- Every line is real text in the server HTML and is readable with no JavaScript
- While a line is being typed, the full text of the line is available to screen readers at once and the typed copy is hidden; nothing is read letter by letter
- Typing runs once and stops; it never loops, so there is no moving content to stop after the lines are in
- Reduced motion, isPaused and anything inside rdm-still show every line at once
- The Copy button confirms with a polite status message
- The text area scrolls and takes keyboard focus, so long lines are reachable without a mouse
Guidelines
Use it when
- Showing an install or setup command
- A short scripted demo of a command-line tool
Avoid it when
- A real interactive shell
- Long logs (use a log viewer)
Don't
- Putting secrets in the lines
- Typing very long scripts that delay the reader
Design tokens
The semantic tokens this component uses. Change them once and every component follows; see Design tokens.
--rd-color-surface-subtle--rd-color-border-default--rd-color-text-default--rd-color-text-muted--rd-color-focus-ring--rd-radius-control