DocsComponents
Segmented control
One choice out of a few, visible at once.
- 1Group: radiogroup with a name, at least 44 px high
- 2Track: 36 px, muted background, radius 12 px, 3 px inset
- 3Selected segment: white card, 2 px slate ring, label 600
- 4Other segments: label 500 in slate-600; the radio itself is visually hidden
Variants
One look, two or three options. The control switches a mode, for example how a price is counted or how a group is split, and takes the full width of its container.
States
Hover turns the label deep blue, also on the selected segment. Focus draws a 3 px ring around the whole segment. The examples above react to the real pointer and arrow keys.
API reference
A controlled component: the app keeps the value and passes the labels from its translations.
| Prop | Type | Default | Description |
|---|---|---|---|
name | string | – | Shared name of the radio inputs. |
label | string | – | Name of the group for screen readers (aria-label of the radiogroup). |
value | string | – | Value of the selected segment. |
options | list of { value, label } | – | Two or three equal options; long labels are truncated. |
onChange | function (value) | – | Called with the new value; the selection is controlled by the app. |
className | string | – | Extra classes for the outer wrapper. |
Accessibility
- Built from native radio inputs inside a radiogroup with a name: arrow keys move the selection, a screen reader announces “2 of 3, selected”.
- The radios are visually hidden but stay in the accessibility tree; the whole segment is the click target.
- The track is 36 px, but each segment extends its hit area 4 px up and down, and the group is at least 44 px high.
- Selection is not shown by colour alone: the selected segment becomes a white card with a ring and a heavier label.
- Contrast: unselected label 6.9:1 on the track, selected label 20.2:1 on white, hover 7.7:1.