Skip to content
ArcadiaDesign
Four models are available to this workspace.

TSX

One strip, one behaviour. pill, the default: the current tab on a fill-3 pill that slides to the next tab on the morph spring, for panel headers and page sections, sm where the pane is narrow. segmented, the Segmented Control's thumb, for a view switch whose options each keep a panel. A tab's icon sits beside its label, framed and stroked by the label's text; the selection is the indicator's.

Tabs or a Segmented Control? Tabs switch between panels of content and carry the tab roles. To pick a value, such as a setting or a filter, with no panel of its own, use a Segmented Control.

Examples

Panel header

The strip at sm, with icons, heading a side panel.

3 files changed.

Segmented

The Segmented Control's look, when each option still has its own panel.

Appearance and size

rootStyle takes where the strip sits (margins, self-alignment, flex and grid placement, size bounds) and the knobs below, each a token of its kind. A colour, a raw length or any other property is a type error: a look that comes up twice becomes a variant.

TSX
--tab-h
Ref<Control>Default var(--control-sm)
Tab height.
--tab-px
Ref<Space>Default var(--space-2)
Tab inline padding.
--tabs-gap
Ref<Space>Default var(--space-0-5)
Gap between tabs.
--tab-fg
PaintDefault var(--text-3)
Tab label colour at rest.
--tab-fg-hover
PaintDefault var(--text-2)
Tab label colour under the pointer.
--tab-fg-active
PaintDefault var(--text-1)
The current tab's label colour.
--tab-fg-disabled
PaintDefault var(--text-4)
A disabled tab's label colour (the current tab keeps its own).

The knobs go on TabsList and every tab inherits them. A disabled tab drops to --tab-fg-disabled; the current tab keeps its colour. A segmented strip takes the Segmented Control's knobs instead.

Tabs follow the APG pattern: a tablist with one tab stop, and panels labelled by their tabs. Focus never drops to the page when a tab is activated. A disabled tab stays in place at text-4 and is skipped by the arrow keys.

←→
Move focus between tabs
EnterSpace
Activate the focused tab, unless activateOnFocus already did
HomeEnd
First or last tab

Tabs

value
string
The active tab (controlled).
defaultValue
string
The initially active tab.
onValueChange
(value: string, details: { event: Event }) => void
Called when the active tab changes.
orientation
"horizontal" | "vertical"Default "horizontal"
rootStyle
RootStyle
Typed StyleX override: where the tabs sit.
className
string
A product's hook class (being retired: new code sets rootStyle; ui.lint's kit-classname counts the rest).

Rest props go to <div> props.

appearance
"pill" | "segmented"Default "pill"
pill (the default): 24px tabs, the active one on a 6% fill that slides to the next tab (panel headers, pages). segmented: the SegmentedControl look (track + sliding thumb).
size
"sm" | "md"Default "md"
stretch
booleanDefault false
segmented only: tabs share the full width.
activateOnFocus
booleanDefault false
Activate a tab as soon as arrow keys focus it.
rootStyle
TabsListStyle
Typed StyleX override: where the strip sits and its --tab-* knobs (segmented: SegmentedControl's).
className
string
A product's hook class (being retired: new code sets rootStyle; ui.lint's kit-classname counts the rest).

Rest props go to <div> props.

valuerequired
string
Matches a TabsPanel's value.
disabled
boolean
Text-4 and skipped.
className
string
A product's hook class (being retired; ui.lint's kit-classname counts the rest).

Rest props go to <button> props.

valuerequired
string
The tab this panel belongs to.
className
string
A product's hook class (being retired; ui.lint's kit-classname counts the rest).

Rest props go to <div> props.