Skip to main content
ComponentsNavigation

Component · Navigation

List

Composable collection view: leading/primary/secondary/status/badge/actions/shortcut; group headers; CollectionState+SelectionModel+typeahead; single/multi/range; search; density; virtual window; ScrollArea sync.

Kind
widget
Input
interactive
Canvas
120×40

Live preview

Loading terminal preview.

Static terminal poster. Choose Run live to start the Rust demo.

Ghosttylist/selection
Loading terminal poster…
○ loading posterNo input — rendered state only
List · exact mounted Rust story

01 · Purpose

What it is for

Composable collection view: leading/primary/secondary/status/badge/actions/shortcut; group headers; CollectionState+SelectionModel+typeahead; single/multi/range; search; density; virtual window; ScrollArea sync.

Best fit: Navigation · navigation · widget

02 · Behavior

What the mounted story proves

  1. 01

    List

    Representative 120×40 terminal state.

  2. 02

    Passive paint

    No keyboard or pointer action is claimed by this representative story.

  3. 03

    Evidence stays explicit

    5 covered · 9 partial · 3 missing axes.

03 · Implement

Install, then start from exact code

Install

cargo add termrock --git https://github.com/tailrocks/termrock.git --rev 5283c2acf9154d0cfcd37b1ffe821c00faf90ea2

Add TermRock once. Keep domain effects in the host application.

Minimal implementation

Exact Rust setup used by list/selection.

Open to load code.

04 · Adapt

Variants and composition

Variants

Use the preview Variant menu when alternate registered stories exist. Each selection mounts a fresh configuration.

Composition

Navigation · navigation · widget

05 · Reference

API, tokens, accessibility

Tokens

DesignSystemInspect exact story code for roles and capability projection.

Accessibility

Input contract mountedNo input claim in the representative story.

Contract

Evidence in progress5/23 axes covered

06 · Go deeper

Advanced guidance

Authored implementation guidance

Purpose. Present a vertical collection where each row has a stable identity for selection, activation, and hits — without TermRock owning filtering, sorting, or domain models. Ideal for navigation, pickers’ result bodies, and task lists.

When to use / when not

Use ListPrefer
Navigation, pickers’ results, task lists—
Rows with primary + optional metaComposedRow contraction
Multi-column relational dataTable / DataTable
Hierarchical dataTree
Fuzzy query + resultsPicker / Command palette

Anatomy

viewport · row[] · each row: leading · primary label · secondary · badge · shortcut · selection gutter

Under width pressure, drop order is shortcut → badge → secondary → leading → primary last (ComposedRow).

Public API

APIWhy
ListRow::itemFast path for primary-only rows
List::new(&[rows], &tokens)Borrowed projection — no clone of domain data
ListState::new(selected)Selection + scroll owned by state
handle_key / mouseTyped Outcome only

State ownership

TermRockConsumer
Selected id, offset, hover, hitsRow data, filter, sort
Contraction of row partsLabels, enablement, loading flags
Navigation side effects on Activate

Typed outcomes

Outcome::{Ignored, Changed, Activated(id), …} — activation means “user chose this id”; open a file or run a tool outside the list.

Variants

  • RowRole item vs section headers.
  • Loading rows show busy leading.
  • Disabled rows skip activation and focus cycle.
  • Multi-select when mode enabled (stable ids only).

Sizes

Min useful ~3 rows + chrome. Prefer filling a pane; fullscreen N/A (use overlay host for modal lists).

Density

Tokens pad; default one line per row for virtualization-friendly paint.

Keyboard

Move / page / home-end via collection intents or handle_key. Enter → Activated. Esc is usually host/overlay (caller-owned).

Mouse

Wheel scrolls; click selects/activates. Hit regions track painted rows only.

Focus

List is one screen target; selection is the within-list focus. Blur keeps selected id.

Responsive

Stories: list/narrow. Drop meta before primary identity.

Accessibility / colorless

Gutter marker for selection (› / *), not fill color alone. Disabled uses TextDisabled.

Unicode

Stories: list/unicode. CJK/wide labels use display width; ASCII glyph set available via tokens.

Composition

Sidebar, TaskRail, Picker results, SessionPicker body, CommandPalette body.

Theming

Role::Selection, Role::Text, Role::TextMuted, Role::TextDisabled, Role::Focus.

Custom recipe

Use DesignTokens density + GlyphSet::Ascii under Minimal profile; avoid per-row RGB for selection.

Performance

Paint O(visible rows). For 10k+ keep only the viewport projection; see docs/design/streaming-performance.md and data_view VirtualWindow patterns.

Testing

  • Stories: list/selection, list/narrow, list/unicode, list/ascii
  • documentation_examples::list_documentation_example
  • Contract axes: keyboard / mouse / focus / nonColor / unicode / narrow

Complete application example

filter domain → project visible ListRow[] → List::render
on Activated(id) → open detail / start tool
on resize → keep selected id, clamp scroll
Ownership boundary

TermRock owns reusable terminal rendering and interaction state. The host owns domain data, policy, persistence, authorization, and side effects.

Evidence status

5 covered, 9 partial, and 3 missing contract axes. Missing evidence is not a behavior claim.