States
Active segment uses --background-inverse-primary thumb with --shadow-s. Default segments are transparent. Disabled segments use muted text and ignore pointer events.
Active (first) / Default / Default — 3 segments
With double-color start-slot icons
Disabled segment (middle)
Color tokens
| State | Element | Token |
|---|---|---|
| Active | Thumb background | --background-inverse-primary |
| Active | Thumb shadow | --shadow-s |
| Active | Label color | --text-and-icon-brand |
| Active | Icon vector layer | --double-color-outline-inverse |
| Active | Icon bg layer | --double-color-bg-inverse |
| Default | Segment background | transparent |
| Default | Label color | --text-and-icon-primary |
| Default | Icon vector layer | --double-color-outline |
| Default | Icon bg layer | --double-color-bg |
| Disabled | Label color | --text-and-icon-disabled |
| Track | Background | --surface-on-white |
Anatomy
Track contains 2–5 equal-width segments. Each segment is composed of 4 optional/required slots arranged in a horizontal row.
Track with annotated segment slots
ATrack — --surface-on-white
BThumb — --background-inverse-primary
Cstart-slot — IconContainer (dc, optional)
Dlabel — Heading 4, required
Eindicator — Indicator L, optional
Fend-slot — IconContainer (dc, optional)
| Slot | Type | Required | Notes |
|---|---|---|---|
| Track | Container | Required | Holds all segments + sliding thumb. role="group" + aria-label |
| Thumb | Absolute overlay | Auto | Injected by JS. Slides under active segment via transform: translateX() |
| start-slot | IconContainer (dc) | Optional | Left icon. 24×24px. Does not flip in RTL |
| label | Text | Required | Heading 4. Single line — truncates with ellipsis. Gap to icon: --sp-s4 |
| indicator | Indicator · L | Optional | Status dot after label. Gap: --sp-s8. Collapses when hidden |
| end-slot | IconContainer (dc) | Optional | Right icon. 24×24px. Does not flip in RTL |
Layout
All spacing uses SP tokens. Track fills 100% of its container. Segments always share width equally — no horizontal scrolling.
Spacing tokens
| Element | Property | Token | Value |
|---|---|---|---|
| Track | height | --sp-s56 | 56px |
| Track | padding (all sides) | --sp-s4 | 4px |
| Track | border-radius | --sp-s20 | 20px |
| Thumb | height | --sp-s48 | 48px |
| Thumb | border-radius | --sp-s16 | 16px |
| Segment | height | --sp-s48 | 48px |
| Segment | padding horizontal | --sp-s12 | 12px |
| Segment | padding vertical | --sp-s10 | 10px |
| Segment | border-radius | --sp-s16 | 16px |
| Segment | gap (icon → label) | --sp-s4 | 4px |
| Segment | gap (label → indicator) | --sp-s8 | 8px |
Layout examples
2 segments — minimum
3 segments — recommended default
4 segments
5 segments — maximum; short labels required
With start-slot icons
RTL (dir="rtl") — segment order reverses, icons do not flip
Animation
The active thumb slides via
transform: translateX() — compositor-friendly. Color transitions use the Patterns/Color curve (linear, 200ms).Live demo — click segments to watch thumb animate
| Element | Property | DS pattern | Duration | Curve |
|---|---|---|---|---|
| Thumb | transform: translateX | Transforming/State/Slow | 300ms | cubic-bezier(0.4, 0, 0.2, 1) |
| Thumb | width | Transforming/State/Slow | 300ms | cubic-bezier(0.4, 0, 0.2, 1) |
| Labels | color | Patterns/Color | 200ms | cubic-bezier(0.25, 0.25, 0.75, 0.75) |
| Icons (.dc-bg, .dc-vector) | fill | Patterns/Color | 200ms | cubic-bezier(0.25, 0.25, 0.75, 0.75) |
Curve rationale —
Thumb uses standard-ease-in-out because it moves within the screen (Rule: Transforming/State).
Colors use linear because there is no geometry change — only a color swap (Patterns/Color).
Reduced motion —
@media (prefers-reduced-motion: reduce) sets --sc-thumb-motion and --sc-color-motion to 0ms linear.
The thumb jumps instantly; labels and icons switch without transition.
Usage
Segmented Control is best for switching between a small set of persistent, mutually exclusive views or modes.
When to use
- 2–5 options that are mutually exclusive
- Persistent mode switching (view mode, sort order, content type)
- The user needs to compare options before choosing
- All options should always be visible — none hidden behind overflow
When not to use
- More than 5 options — use a Select or bottom sheet instead
- Independent toggles (on/off per item) — use individual Toggle Switches
- Navigation between pages — use Tabs or bottom navigation
- Labels are long or variable — they will truncate with ellipsis
Related components
| Component | Use instead when… |
|---|---|
| Tabs | Switching between full page views or sections with scroll position |
| Toggle Switch | Each option is independent (on/off), not mutually exclusive |
| Select (Dropdown) | More than 5 options, or options need a description/icon beyond a short label |
| Radio Button Group | Form context where options are listed vertically and need a visible label above |
Accessibility
All segments are focusable
<button> elements. The track has role="group" with a descriptive aria-label. Active state is communicated via aria-pressed.Roles and ARIA
| Element | Role | Attribute | Value |
|---|---|---|---|
Track (.segmented-control) | group | aria-label | Descriptive name, e.g. "View mode" |
| Active segment | button (implicit) | aria-pressed | "true" |
| Inactive segment | button (implicit) | aria-pressed | "false" |
| Disabled segment | button (implicit) | aria-disabled + disabled | "true" |
Keyboard navigation
| Key | Behavior |
|---|---|
| Tab | Moves focus into the control (first or last focused segment) |
| Shift+Tab | Moves focus out of the control |
| Tab within | Moves focus to the next segment |
| ← Arrow | Moves focus to the previous segment (wraps around) and activates it |
| → Arrow | Moves focus to the next segment (wraps around) and activates it |
| Space / Enter | Activates the focused segment; updates aria-pressed |
All segments are in the tab order (
tabindex="0").
Do not suppress outline on .sc-segment — the browser default focus ring is sufficient.
Minimum tap target: --sp-s48 height (enforced by segment height).
Full accessibility spec: specs/components/segmented-control/segmented-control-a11y.md