Overview
Composite tabs root that coordinates tab list, tab triggers, and their content panels.
Usage
Tabs is a compound component. Import the parent once and compose its
leaves via the namespace API: Tabs.List, Tabs.Trigger, and Tabs.Panel.
The leaves remain importable individually for à-la-carte builds — see
@lostgradient/cinder/tab, @lostgradient/cinder/tab-list, and @lostgradient/cinder/tab-panel.
Caller-owned panels
Use Tabs.Panel for ordinary tabs where each trigger owns one rendered panel.
When the selected value controls one stable external surface, pass that panel
id through Tabs.Trigger's controls prop and render the panel yourself:
This keeps Cinder in charge of roving tabindex, activation, disabled state, and tab styling while the caller owns an imperative or stateful panel element. Give the tabs explicit ids so the external panel can label itself with the active tab.
Trailing badges and counts
Each Tabs.Trigger accepts a trailing snippet for badges, counts, or status
dots. Render the library Badge inside it for idiomatic styling — there is no
separate badge class to learn:
The trailing wrapper is aria-hidden, so its content is omitted from the
tab's accessible name. Any count that carries meaning must therefore also live
in the tab's visible children (the accessible name) — never rely on the
trailing badge alone to convey it.
When to use
- Switching between several panels of related content under one heading area.
- Building the WAI-ARIA tabs pattern with shared keyboard navigation and activation rules.
- Picking one of two to five short values inline — use segmented-control instead.
- Showing ordered progress through a wizard — use steps instead.
Examples
Basic tabs
Three tabs with associated panels; clicking a tab switches the panel. Uses the Tabs namespace API.
Fill pane tabs
Tabs can fill a bounded flex pane so the active panel takes the remaining height.
Vertical tabs with keyboard navigation
A vertical tablist: focus a tab and use ↑/↓ to move. The focus ring must render complete on all sides even though the tab list is a clipping (overflow) container.
Tabs with trailing badges
Tabs use a decorative `trailing` snippet (wrapped in aria-hidden) for badges and counters. The accessible name only includes the visible label.
Tabs with keyboard navigation
Focus a tab and use ←/→ to move; horizontal tablists activate on focus per the WAI-ARIA pattern.
Props
| Name | Type | Default | Required | Bindable | Description |
|---|---|---|---|---|---|
value | text | '' | bind | Bound active tab value. | |
onValueChangeRequest | (next: string) => stringvoid | Intercept a proposed tab value before the bindable value is written. Return a replacement value to transform it. | |||
onValueChange | (next: string) => void | Notify after the bindable value has been committed. | |||
orientation | 'horizontal' | 'vertical' | 'horizontal' | Layout orientation. Affects which arrow keys move between tabs. | ||
fill | boolean | false | Fill the available space when Tabs is placed inside a bounded flex parent, letting the active TabPanel occupy the remaining height. | ||
activateOnFocus | boolean | When true (default for horizontal), focusing a tab also activates it (the panel updates immediately). Vertical defaults to manual activation — the user moves focus with arrows, then presses Enter or Space. | |||
children | snippet | req | Tab and TabPanel children. |