Skip to content
Component installs need the registry setup
VegaStack Design

Terminal

A mono command block on the card surface with a phosphor prompt glyph and a fixed trailing copy action.

Status
stable
Since
0.1.0
Accessibility pattern
decorative prompt + real text

Last updated

Install
pnpm dlx shadcn@latest add @vegastack/button
✓ Installed 1 component

Install

Configure registry credentials first using the Quickstart. Before copying this item or any transitive registry dependency, verify the signed manifest and save the exact bytes for Terminal before installation. Retain the digest printed by this command.

pnpm exec vegastack-design verify terminal

Install with the pinned shadcn CLI. Bare shadcn does not verify VegaStack signature or integrity.

pnpm dlx shadcn@4.21.0 add @vegastack/terminal

Run the exact offline --post-write command printed by the preflight, using its saved item path and independently retained --expected-integrity digest. Use the saved preflight for every transitive registry dependency too; stop on any mismatch before using the components.

The same command installs the registry items it composes: @vegastack/copy-button, @vegastack/use-overflow.

Usage

import { Terminal } from "@/components/ui/terminal";

<Terminal
  title="Install"
  lines={[
    "pnpm dlx shadcn@latest add @vegastack/button",
    { output: "✓ Installed 1 component" },
  ]}
/>;

Anatomy

Terminal is a compound component. Every exported part, with the data-slot it renders (generated from the canonical source):

Terminal — data-slot="terminal" | "terminal-command-row" | "terminal-copy" | "terminal-header" | "terminal-line" | "terminal-prompt"
TerminalBody — data-slot="terminal-body"

Examples

Install
pnpm dlx shadcn@latest add @vegastack/button
✓ Installed 1 component

Multi-line, custom prompt

Each line is a plain string (a command) or { output: string } (dimmed, no prompt glyph). The prompt glyph — the sanctioned "terminal prompt glyph" --brand marker role — defaults to $ and is overridable.

Setup
pnpm install
pnpm run tokens:build
✓ tokens built: dist/theme.css
pnpm run registry:build

Copying

The command row composes the icon-only CopyButton at its inline end. The command pane scrolls independently, so the action remains visible even when a command is long. It copies every command line (not output lines), joined by newline, unless you pass an explicit copyValue; successful writes swap the copy icon for the standard success check.

API Reference

PropTypeDefaultDescription
lines*(string | TerminalLine)[]—The lines to render, top to bottom. A plain string is shorthand for { command: string }. Content is fully caller-supplied (no timestamps, no randomness) — deterministic by construction, so it's VRT-stable.
aria-labelstringderived from `title`Accessible name for the scrollable command pane, which is a keyboard focus stop while it overflows. Overrides the default, which names the pane from the visible title. Mirrors ScrollArea: the label is intercepted here and applied to the focusable element, not to the outer block.
aria-labelledbystringthe visible title elementId of an element naming the scrollable command pane. Takes precedence over the visible title; ignored when aria-label is set.
copyValuestringderived from command linesValue copied by the trailing CopyButton. Defaults to every command line (not output lines) joined with newlines.
promptstring'$'The prompt glyph shown before each command line — the sanctioned "terminal prompt glyph" --brand marker role (audit 17-brand-direction §Color & surface).
titleReact.ReactNode'Terminal'Small mono label in the header bar, in sentence case.

Data attributes and CSS variables on Terminal

AttributeValues
data-slot"terminal" | "terminal-command-row" | "terminal-copy" | "terminal-header" | "terminal-line" | "terminal-prompt"

Accessibility

  • The prompt glyph is decorative (aria-hidden) — command text itself is real, readable text.
  • The composed CopyButton carries its own accessible name ("Copy command" / "Copied command") and announces the copy via a visually-hidden live region.
  • The command pane is keyboard-focusable while it actually scrolls, and not otherwise. A scrollable region that cannot be focused is unreachable without a pointer; a pane whose commands fit needs no tab stop, and adding one would put a dead stop in front of every keyboard user on a page full of one-line install snippets. The pane measures itself live (useOverflow), so the tab stop appears and disappears with the viewport width. Focus is shown as an inset outline: an outward one is not painted at all here, because the block's root is overflow-hidden and scroll-fade-x masks the pane to its own border box. A border tint is not an option either — forced-colors: active replaces border-color, which would leave the pane with no indicator in the forced palette.
  • The pane is always announced as a named group, labelled by the visible title — the name and the role do not move with the measurement, because a role that appeared and vanished under a screen reader as the window resized would be a worse defect than the tab stop it removed — so title="Install" reads as "Install, group". A bare focusable div would announce as an unnamed stop: it maps to the generic role, which prohibits naming, so an aria-label on it is not reliably exposed. group is deliberate rather than region, which is a landmark — several install snippets on one page should not add several landmarks. Override the name with aria-label or point aria-labelledby at your own element; both are applied to the pane, not the outer block.
  • Content is fully caller-supplied — no timestamps, no randomness — so the block is deterministic and safe for visual capture.
KeyAction
TabMove focus to the command pane when it scrolls (announced by its name), then on to the copy button.
← / →Scroll a clipped command horizontally while the pane has focus.
Enter / SpaceCopy the command, when the copy button has focus.
ContractStates tested
Behaviourdefault, copied
Accessibilitybrowser-accessibility-test, focus-visible, keyboard, labeled, native-or-base-ui-semantics
Visualdefault

Do / Don't

Do
Use Terminal for install snippets and short command sequences with real, copyable text.
Don't
Reach for a Terminal to render program output the reader cannot copy — a CodeBlock or a plain pre carries that better.

On this page