Skip to main content

TerminalWorking

Transcriptterminal

The in-turn footer row pinned last in a transcript: a spinner/diamond glyph, a label, elapsed time, token spend and a stop control — the three facts and an exit the human needs while the agent runs.

import { TerminalWorking } from "@elabs-ai/components-terminal";
Install
npm install @elabs-ai/components-tokens @elabs-ai/components-ui @elabs-ai/components-terminal

Skipping the @source line is the most common first failure: Tailwind does not scan node_modules, so every component renders unstyled. The one-time wiring

Prompt for your coding agent

Paste 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

Examples

6 live 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

PropTypeDescription
labelstringWhat the turn is doing right now. Defaults to the shared "Waiting for response…" copy.
elapsedMsnumberElapsed time in the current turn, in milliseconds. Rendered via `formatElapsed`.
tokensnumberToken count for the turn so far, rendered with the download-token marker (⇣).
isStreamingboolean`true` once content is actively arriving — swaps the spinner for the solid diamond.
onStop() => voidRenders a focusable stop control, reachable by keyboard, while the turn runs.
stopShortcutstringKeyboard-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.
showScrollToBottombooleanRenders a "scroll to bottom" affordance.
onScrollToBottom() => void
variantTerminalVariantGutter grammar. Omitted, the row inherits the surrounding `TerminalSurface`; passed, it overrides it, so a row still renders correctly outside any surface.

Also accepts: Omit< TerminalRowProps, "gutter" | "gutterLabel" | "children" >

Theming

The tokens each state resolves to. Change the token and every theme follows.

StateToken
trailingtext-terminal-muted tabular-nums