components — Terminal UI Component Library

Terminal UI Component Library

389 React (Ink) components powering the terminal UI. From low-level design system primitives to complex interactive dialogs. Includes PromptInput, Messages rendering, StructuredDiff viewer, model/theme pickers, MCP server dialogs, agent status views, and full settings panels.

31
Groups
389
Files
~82k
Lines
TS/TSX
Language

🔵 Ink (React Terminal) 🟢 Design System 🟡 Virtual Scrolling 🔴 Accessibility

🏢 Think of It Like a Building

If Claude Code were a building, the components module is every room and piece of furniture inside it. The design-system primitives (Dialog, Tabs, Pane, ThemedText) are the standardized building materials—walls, doors, and light switches that every room shares. PromptInput is the front desk where visitors (users) speak. Messages is the main hall displaying the conversation. FullscreenLayout is the blueprint that decides where the hall, front desk, and side rooms go. Specialized rooms like permissions, mcp, and Settings are offices where specific business gets handled. And VirtualMessageList is the clever concierge who only turns on the lights in rooms that guests can actually see, keeping energy costs (render cycles) low.

Architecture

Component hierarchy from App.tsx root through layout, messages, and input layers:

flowchart TD
  App["App.tsx\n(Root Providers)"]
  App --> FPS["FpsMetricsProvider"]
  App --> Stats["StatsProvider"]
  App --> AppState["AppStateProvider"]

  AppState --> FSLayout["FullscreenLayout\n(ScrollBox + Sticky Header)"]

  FSLayout --> Logo["LogoV2/\n(Header + Status)"]
  FSLayout --> MsgList["VirtualMessageList\n(Virtual Scroll)"]
  FSLayout --> Prompt["PromptInput/\n(REPL Input)"]
  FSLayout --> ModalOverlay["Modal Overlay"]

  MsgList --> Messages["Messages.tsx\n(Normalize + Group)"]
  Messages --> Message["Message.tsx\n(Route by Type)"]

  Message --> UserText["UserTextMessage"]
  Message --> AssistantText["AssistantTextMessage"]
  Message --> ToolUse["ToolUseMessage\n+ Progress"]
  Message --> Thinking["ThinkingMessage"]
  Message --> System["SystemMessage"]

  ModalOverlay --> Dialog["design-system/Dialog"]
  ModalOverlay --> FuzzyPicker["design-system/FuzzyPicker"]
  ModalOverlay --> PermReq["permissions/\nPermissionRequest"]
  ModalOverlay --> SlashCmd["Slash Command Pane"]

  Prompt --> TextInput["TextInput\n(Cursor + Vim)"]
  Prompt --> Typeahead["Typeahead\n(@-mentions)"]
  Prompt --> HistSearch["History Search\n(Ctrl+R)"]

Data Flow

Sequence of events when the user types a message and sees the response rendered:

sequenceDiagram
  participant User as User (Keyboard)
  participant TI as TextInput
  participant PI as PromptInput
  participant REPL as REPL Engine
  participant API as Claude API
  participant Msgs as Messages.tsx
  participant VML as VirtualMessageList
  participant Ink as Ink Renderer

  User->>TI: Keystroke events
  TI->>PI: onChange(buffer)
  PI->>PI: Typeahead / History hooks
  User->>PI: Enter (submit)
  PI->>REPL: onSubmit(userMessage)
  REPL->>API: Stream request
  API-->>REPL: Token chunks
  REPL->>Msgs: Append message blocks
  Msgs->>Msgs: Normalize, collapse, group
  Msgs->>VML: Updated message list
  VML->>VML: Binary search visible range
  VML->>Ink: Render visible messages only
  Ink->>User: Terminal output (blit-optimized)

🚶 Step-by-Step Narrated Walkthrough

Follow a single user message from typing to rendered response as it flows through the components pipeline:

  1. Keystroke Capture — The user presses a key. Ink’s useInput hook fires inside TextInput.tsx, updating the internal buffer and cursor position. In vim mode the keystroke is routed through the vim state machine first.
  2. PromptInput Processing — PromptInput.tsx (2,338 lines) receives the updated buffer. If the character is @, the typeahead menu opens via useTypeahead. Arrow keys trigger useArrowKeyHistory to cycle through past inputs.
  3. Suggestion Overlay — usePromptSuggestion queries model-powered completions. If matches exist, a FuzzyPicker overlay appears in the modal slot, navigable with arrow keys.
  4. Submit — User presses Enter. PromptInput calls onSubmit(userMessage), passing the text to the REPL engine. The input buffer is cleared and the prompt resets.
  5. API Streaming — The REPL engine sends the message to the Claude API. Token chunks arrive via streaming. Each chunk is appended to the in-progress AssistantMessage in state.
  6. Message Normalization — Messages.tsx (833 lines) receives the updated message array. It collapses consecutive same-type blocks, groups tool_use/tool_result pairs, and filters for brief mode if active.
  7. Lookup Tables — buildMessageLookups() creates indices: tool name → block, UUID → message index, in-progress tool IDs. These are passed as props to avoid re-computation in children.
  8. Virtual Scroll Calculation — VirtualMessageList uses cached heights (WeakMap) and cumulative sums. A binary search finds the first visible message index given the current scrollTop. Only messages in the viewport plus a small buffer are rendered.
  9. Message Routing — Each visible message hits Message.tsx (626 lines), which routes by type: UserTextMessage, AssistantTextMessage, ToolUseMessage (with spinner while shouldAnimate=true), or ThinkingMessage.
  10. Terminal Render — Ink compiles the React tree to terminal escape sequences. Blit caching ensures only changed cells are redrawn. Memoized subtrees (LogoHeader, completed Messages) produce zero writes, keeping the frame budget under 16ms even for 2,800-message transcripts.

Key Components

ComponentFileLinesRole
AppApp.tsx~55Root provider wrapper: FpsMetrics, Stats, AppState contexts
FullscreenLayoutFullscreenLayout.tsx~350Layout manager: scrollable area, sticky header, modal overlay, floating companion
MessagesMessages.tsx833Memoized transcript renderer: normalizes, collapses, groups, filters messages
MessageMessage.tsx626Single message router: dispatches to UserText, AssistantText, ToolUse, etc.
VirtualMessageListVirtualMessageList.tsx~500Virtual scroll: binary search visible range, height caching, search indexing
PromptInputPromptInput/PromptInput.tsx2,338Primary REPL input: vim/normal/voice modes, history, typeahead, buddy notifications
TextInputTextInput.tsx~280Base text field: cursor rendering, voice waveform, animation frame support
Dialogdesign-system/Dialog.tsx~150Modal dialog: title/subtitle, Esc to cancel, Enter to confirm keybindings
Tabsdesign-system/Tabs.tsx~200Tabbed interface: keyboard nav, fixed content height, tab index tracking
FuzzyPickerdesign-system/FuzzyPicker.tsx~300Search dropdown: async filtering, cursor nav, preview pane, multi-action
ThemeProviderdesign-system/ThemeProvider.tsx~120Theme context: auto/dark/light modes, live OSC 11 terminal watching
ThemedTextdesign-system/ThemedText.tsx~60Color-aware text: theme color lookup, hover color context
Panedesign-system/Pane.tsx~80Command pane wrapper: colored top divider, padding, modal-aware rendering
PermissionRequestpermissions/PermissionRequest.tsx~250Tool permission dispatcher: routes Bash, FileEdit, WebFetch to specialized dialogs
SpinnerSpinner.tsx~85Loading spinner: frame-based animation, emoji rotation, custom patterns

Sub-Modules

PromptInput/

Primary REPL input system — 21 files handling all user input modalities.

  • Normal, Vim, and Voice input modes
  • Arrow-key history & Ctrl+R search
  • @-mention typeahead & prompt suggestions
  • Multiline editing & inline paste

Messages/

Message rendering pipeline — 33+ files for all block types and transcript display.

  • Normalization, collapsing & grouping
  • VirtualMessageList (lazy render + binary search)
  • Specialized renderers: text, tool use, thinking, attachments
  • Brief mode filtering & transcript mode

agents/

Agent task status views — 13 files for coordinator and sub-agent tracking.

  • Agent task progress & status badges
  • Coordinator hierarchy display
  • Parallel task monitoring

design-system/

Core terminal UI primitives — 16 files providing the shared component vocabulary.

  • Dialog, Tabs, Pane, ProgressBar
  • FuzzyPicker, ThemedText, ThemeProvider
  • Color tokens & layout utilities

permissions/

Tool permission dialogs — 15 files gating bash, file edit, web fetch, and more.

  • Risk assessment display
  • Approve / Reject keybinding flow
  • Sticky footer for scroll-aware prompts

mcp/

MCP server management — 12 files for server connections and approval dialogs.

  • Server connection status
  • Approval workflows
  • Tool discovery & listing

Configuration

SettingTypeDefaultDescription
theme'dark' | 'light' | 'auto''auto'UI theme; auto watches terminal via OSC 11 escape sequence
mode (PromptInput)'normal' | 'vim' | 'voice''normal'Input editing mode
multilinebooleanfalseEnable multi-line prompt editing (Shift+Enter for newline)
visibleCount (FuzzyPicker)number10Max items visible in the picker dropdown
direction (FuzzyPicker)'down' | 'up''down'Dropdown direction relative to input
contentHeight (Tabs)numberautoFixed height for tab content area (prevents layout shift)
borderStyle (Box)'single' | 'double' | 'round' | 'bold''single'Border style for Ink Box components
isCancelActive (Dialog)booleantrueWhether Esc/Ctrl-C close the dialog (disable when editing text inside)
style (Message)'condensed' | undefinedundefinedCondensed rendering for compact views

Directory Map

Source tree for components
components/
├── App.tsx                        ← Root provider wrapper
├── FullscreenLayout.tsx           ← Layout: scroll + sticky header + modals
├── Messages.tsx                   ← Transcript normalizer & renderer (833 LOC)
├── Message.tsx                    ← Single message router (626 LOC)
├── VirtualMessageList.tsx         ← Virtual scroll with binary search
├── TextInput.tsx                  ← Base text field with cursor & vim
├── Spinner.tsx                    ← Animated loading indicators
├── HighlightedCode/               ← Syntax highlighting wrapper
├── StructuredDiff/                ← Side-by-side diff viewer
│
├── PromptInput/                   ← REPL input system (21 files)
│   ├── PromptInput.tsx            ← Main input component (2,338 LOC)
│   ├── inputModes.ts              ← Normal / Vim / Voice state machines
│   └── ...
│
├── messages/                      ← Message block renderers (33 files)
│   ├── UserTextMessage.tsx        ← User input display
│   ├── AssistantTextMessage.tsx   ← Assistant response display
│   ├── ToolUseMessage.tsx         ← Tool invocation + progress
│   ├── ThinkingMessage.tsx        ← Thinking block (collapsible)
│   └── ...
│
├── design-system/                 ← UI primitives (16 files)
│   ├── Dialog.tsx                 ← Modal dialogs
│   ├── Tabs.tsx                   ← Tabbed interface
│   ├── FuzzyPicker.tsx            ← Search dropdown
│   ├── Pane.tsx                   ← Command pane wrapper
│   ├── ThemedText.tsx             ← Color-aware text
│   ├── ThemeProvider.tsx          ← Theme context + OSC 11 watching
│   └── ProgressBar.tsx            ← Progress indicators
│
├── agents/                        ← Agent status views (13 files)
├── permissions/                   ← Tool permission dialogs (15 files)
├── mcp/                           ← MCP server management (12 files)
├── tasks/                         ← Task progress tracking (12 files)
├── Spinner/                       ← Spinner variants (12 files)
├── CustomSelect/                  ← Dropdown menus (10 files)
├── FeedbackSurvey/                ← In-app surveys (9 files)
├── LogoV2/                        ← Branding & status feeds (15 files)
├── hooks/                         ← Hook mode dialogs (6 files)
├── wizard/                        ← Multi-step setup flows (5 files)
├── sandbox/                       ← Sandbox interactions (5 files)
├── shell/                         ← Shell output display (4 files)
├── Settings/                      ← Configuration dialogs (4 files)
├── HelpV2/                        ← Help system UI (3 files)
├── diff/                          ← Diff/patch rendering (3 files)
├── ui/                            ← Tree select, ordered lists (3 files)
├── memory/                        ← Memory context indicators (2 files)
├── teams/                         ← Team/swarm management (2 files)
├── TrustDialog/                   ← Trust & security decisions (2 files)
├── ManagedSettingsSecurityDialog/  ← Security policy enforcement (2 files)
├── grove/                         ← Code grove integration (1 file)
├── skills/                        ← Skill management (1 file)
├── ClaudeCodeHint/                ← Tutorial hint popover (1 file)
├── DesktopUpsell/                 ← Desktop app marketing (1 file)
├── LspRecommendation/             ← LSP server suggestions (1 file)
└── Passes/                        ← Guest pass management (1 file)