import { TerminalWorking } from "@elabs-ai/components-terminal";npm install @elabs-ai/components-tokens @elabs-ai/components-ui @elabs-ai/components-terminalPaste it into Claude Code, Cursor, Codex or any other coding agent. Text in [brackets] is yours to fill in.
Add the brand-ui TerminalWorking component (from @elabs-ai/components-terminal) to this project. 1. Read https://elabs-ai.com/llms.txt first: it maps every package and the rules. If you can use MCP servers, connect https://elabs-ai.com/mcp and use its search, docs and tokens tools. If not, run the same lookups in the terminal: `npx -y @elabs-ai/components-cli search "<what you need>"` and `npx -y @elabs-ai/components-cli docs <Component>`. 2. Look TerminalWorking up before writing code: `npx -y @elabs-ai/components-cli docs TerminalWorking` prints its real props, variants, what it pairs with and what to avoid. 3. If @elabs-ai/components-terminal is not installed yet: `pnpm add @elabs-ai/components-tokens @elabs-ai/components-ui @elabs-ai/components-terminal` (or `npm install @elabs-ai/components-tokens @elabs-ai/components-ui @elabs-ai/components-terminal`). If this is the first brand-ui package in the project, wire it once: import `@elabs-ai/components-tokens/styles.css` plus the `themes/light.css` and `themes/dark.css` stylesheets in the CSS entry, add one Tailwind `@source` line per installed @elabs-ai package (Tailwind does not scan node_modules, so without it everything renders unstyled), and wrap the app root in `ThemeProvider` from `@elabs-ai/components-tokens`. 4. Use it here: [the screen or file, and what it should show] 5. Rules: use only @elabs-ai/components-* components and the semantic tokens — no raw colours, no raw font sizes, no arbitrary Tailwind values. Look up each component's real props with the docs tool before you use it; never guess a prop. 6. Done means: the typecheck passes, `npx -y @elabs-ai/components-cli audit src --strict` reports nothing, and you have opened the app and looked at every screen you touched in the light and the dark theme.
Avoid
- Running a setInterval to advance the spinner or tick elapsedMs — the spinner is a pure CSS keyframe and elapsedMs is a caller-supplied snapshot (D5); this component owns no timer.
- Announcing the ticking elapsed time or token count in the live region — exactly one role=status announces `label`; the stats are plain, non-live text or assistive tech is flooded on every re-render.
- Inventing a keyboard shortcut for the stop control — `stopShortcut` is caller-supplied (mirrors SessionHeader's/PermissionModeSelect's `keyHint`); the component never hardcodes a binding.
- Hand-rolling a second compact-number formatter for `tokens` — it renders through `useLocale().formatNumber`, not a bespoke compacter.
Works with
Pairs with
Examples
With Tokens And Shortcut
A caller-supplied label, token count, and a keyboard-shortcut hint on the stop control.
Streaming
Content is actively arriving — the spinner substitutes for a solid diamond (`◆`), the ground-truth grammar for an actively-streaming tool. The `isStreaming` not-ready signal (`.claude/rules/loading-states.md`).
With Scroll To Bottom
The scroll-to-bottom affordance, alongside the stop control.
Label Only
No stats yet — only the label and the spinner render.
In Transcript
Pinned last in a real transcript, exactly where it lives in practice.
API
TerminalWorking
| Prop | Type | Description |
|---|---|---|
label | string | What the turn is doing right now. Defaults to the shared "Waiting for response…" copy. |
elapsedMs | number | Elapsed time in the current turn, in milliseconds. Rendered via `formatElapsed`. |
tokens | number | Token count for the turn so far, rendered with the download-token marker (⇣). |
isStreaming | boolean | `true` once content is actively arriving — swaps the spinner for the solid diamond. |
onStop | () => void | Renders a focusable stop control, reachable by keyboard, while the turn runs. |
stopShortcut | string | Keyboard-shortcut hint shown beside the stop control, e.g. `"Esc"`. Caller-supplied — the real binding is the host app's, so it is never invented here (mirrors `SessionHeader`'s/`PermissionModeSelect`'s `keyHint`). Omit it and the stop control renders with no hint. |
showScrollToBottom | boolean | Renders a "scroll to bottom" affordance. |
onScrollToBottom | () => void | |
variant | TerminalVariant | Gutter grammar. Omitted, the row inherits the surrounding `TerminalSurface`; passed, it overrides it, so a row still renders correctly outside any surface. |
Theming
The tokens each state resolves to. Change the token and every theme follows.
| State | Token |
|---|---|
| trailing | text-terminal-muted tabular-nums |