Designer view

Segmented Control

A row (or column) of connected buttons that lets the user switch between mutually-exclusive views of the same content — list vs grid, day vs week vs month, KB vs MB vs GB unit toggles. Distinct from Tabs (which switches between different *content*), distinct from RadioGroup (which captures form values rather than view state), distinct from Toggle (which is binary, not n-way). Used for content-presentation toggles where the underlying data is the same and the segments select the visual shape.

Also called Toggle group

When to use

Use

For switching between mutually-exclusive views of the same content — list vs grid view, day vs week vs month calendar, KB vs MB vs GB unit toggle, light vs dark vs auto theme. The user picks one; the underlying data stays the same and the segment selects how it is presented.

Avoid

For switching between different content panels — that is `Tabs`. For form values with form submission — that is `RadioGroup` (which is semantically identical but visually distinct as separate radio buttons). For binary on/off — that is `Switch` or `Toggle`. For more than 5 options — that is a `Select` dropdown.

Versus related

  • tabs

    `Tabs` switches between different *content* panels; `SegmentedControl` switches between *view-of-same- content*. The semantic distinction drives the role (`tablist` vs `radiogroup`) and the keyboard model (Tabs may use manual activation; SegmentedControl always uses auto-activation per APG radiogroup).

  • radio-group

    `RadioGroup` is a form field whose selected value submits with the form; `SegmentedControl` is a denser- mutex view-mode toggle that drives UI state without form-field semantics. Both use `role="radiogroup"` with roving-tabindex per APG; the visual style (compact-pill vs spaced-radios) and the value-target (UI state vs form data) are the canonical differences.

  • switch

    `Switch` is binary on/off (a single setting); `SegmentedControl` selects one of multiple mutually- exclusive options. Use SegmentedControl when the choice has more than two values; Switch only when the answer is exactly on or off. SegmentedControl uses `role="radiogroup"`; Switch uses `role="switch"` — different roles, different keyboard contracts.

Segmented Control is a horizontal row of mutually-exclusive options — a denser alternative to a radio group when space is constrained or when the option labels are short. Two variants (standard, icon-only) cover the label spectrum. The pattern shows up in toolbars for view switching, density toggles, time-range pickers, and filter modes. The reference catalogues the segment slot anatomy, the indicator animation contract that survives RTL, the divergence from Tabs (which navigate between panels rather than toggle a value), and the canonical mapping to APG's radio-group pattern.

Highlight
Fig 1.1 · Segmented Control · Designer view
Designer

Figma anatomy

Slot Figma type Hint
root frame Auto-layout horizontal frame; segments share an outer border
segment instance Segment component instance with selected and unselected variants
icon instance Icon component instance per segment; visibility per variant
label text Segment text style; bound to a component property
indicator rectangle Pill or filled rectangle behind the selected segment; position bound to selection
Designer

Token usage per slot

root
radius
  • cornerradius.md
color
  • backgroundcolor.surface.sunken
  • bordercolor.border.subtle
segment
spacing
  • paddingspacing.compact
radius
  • cornerradius.sm
color
  • foregroundcolor.text.muted
  • ringcolor.border.focus
typography
  • sizetext.sm
  • weightweight.medium
icon
color
  • foregroundcolor.text.muted
label
color
  • foregroundcolor.text.muted
typography
  • sizetext.sm
  • weightweight.medium
indicator
radius
  • cornerradius.sm
color
  • backgroundcolor.surface.bg
elevation
  • shadowelevation.sm
Both

Figma ↔ Code property map

FigmaKindCodeNotes
VariantEnumvariantMaps standard / icon-only.
SizeEnumsizesm / md / lg.
OrientationEnumorientationhorizontal / vertical. Affects keyboard model (ArrowLeft/Right vs ArrowUp/Down).
Has IndicatorBooleanhasIndicatorToggles the sliding-indicator slot. Default true; some variants use only foreground-color contrast for selection without a separate indicator.
Segment CountEnumsegments.lengthFigma exposes 2/3/4/5 segment counts as a Variant for preview-time layout review. Code accepts an array of segment definitions.
Selected SegmentEnumvalueFigma exposes "first / second / third selected" as Variant for preview; in code this is a controlled value (the selected segment id).
Has IconsBooleanhasIconsToggles per-segment icons. Required for icon-only variant; optional for standard variant.
Designer

Motion

TransitionDuration token
indicatormotion.duration.fast
segmentColorChangemotion.duration.fast
Easing
motion.easing.standard
Reduced motion
Instant (jump cut)
Designer

Responsive behaviour

BreakpointChange
breakpoint.smAt and below, the canonical default switches to compact density and may force `orientation="vertical"` when the segment count exceeds 3 (avoids overflow on narrow viewports). For icon-only variant, orientation stays horizontal up to 4 segments because icon-only is space-efficient.
breakpoint.mdAbove this width, orientation and size render as authored. Both orientations are valid; choose per layout context.
Both

Internationalisation

RTL · mirroring

Horizontal orientation reverses logically — first segment in source order appears at the inline-start (visual right in RTL). ArrowLeft / ArrowRight follow visual direction (per APG radiogroup canonical): ArrowRight moves to the *previous* segment in RTL, ArrowLeft to the *next*. Vertical orientation is direction-neutral (Up/Down keys unchanged). Indicator animation slides along the logical axis.

Text expansion

Segment labels grow with translation. The control sizes to its widest segment (or to fill the container when `width: full`); long-text languages may force wider segments than designed. Avoid fixed segment widths; allow intrinsic-size growth. Above 4 segments with long-text labels, consider switching to vertical orientation or to Tabs.

Both

Variants, properties, states

Variants

Structurally different versions of the component.

standard icon-only

Properties

The same component, parameterised.

PropertyType
size sm | md | lg
orientation horizontal | vertical
hasIndicator boolean

States

Browser/user-driven (interactive) vs. app-driven (data).

KindStates
interactive
hoverfocus-visibleactivedisabled
data
selected
Both

State transitions

FromToTrigger
selectedselectedUser activates a different segment via Enter / Space or via ArrowKey navigation in roving-tabindex mode (which auto-activates on focus per APG radiogroup contract). The previously-selected segment loses `aria-checked="true"`; the newly-selected segment gains it. The indicator (if present) animates to the new position.
Both

Figma↔Code mismatches

  1. 01
    Figma

    SegmentedControl drawn as Tabs with no visual differentiation

    Code

    A SegmentedControl with `role="radiogroup"` rather than `role="tablist"`

    Consequence

    Designers may use SegmentedControl visually for what is semantically Tabs (switching between different content panels). Implementations following the design ship `role="radiogroup"` for content-switching, breaking the keyboard model (radiogroup uses ArrowKeys with auto-activation; tablist may use manual activation) and misleading SR users about the surface's purpose.

    Correct

    Distinguish at the canonical level: SegmentedControl switches view-of-same-content (list vs grid; day vs week vs month); Tabs switches between different content panels. The semantic distinction drives the role (`radiogroup` vs `tablist`). Document the boundary clearly in `whenToUse.vsRelated`.

  2. 02
    Figma

    Multi-select segmented control drawn (multiple segments highlighted)

    Code

    A canonical SegmentedControl is single-select only; multi-select segments are not segmented control

    Consequence

    Designers compose mocks with two or three segments "active" simultaneously. Implementations following the design ship multi-select; the semantic surface is neither radiogroup (single) nor a clean checkbox group (no visible grouping). The control becomes ambiguous.

    Correct

    SegmentedControl is single-select by canon — `role="radio"` semantics enforce mutual exclusion. For multi-select visual toggles, use a horizontal `<CheckboxGroup>` styled to look segmented; document this as the related pattern, not as a SegmentedControl variant.

  3. 03
    Figma

    Selected segment differentiated by a coloured fill alone

    Code

    Selected segment differentiated by fill PLUS contrast-text PLUS optional border

    Consequence

    Designers may use a single colour change to mark selection. Implementations following the design fail WCAG 1.4.1 (Use of Color) for users with colour-vision deficiencies; SR users hear the same announcement for every segment because the differentiation is purely visual.

    Correct

    Triple-layer selection differentiation: visual (background + foreground contrast + optional weight or border), accessible state (`aria-checked="true"`), and iconographic (an inline checkmark or selected-state icon for icon-only variants). The `aria-checked` is the source of truth; visuals reinforce.

  4. 04
    Figma

    Vertical segmented control drawn but no orientation property documented

    Code

    A SegmentedControl with an `orientation` property switching between row and column layouts

    Consequence

    Designers compose vertical-segmented variants in mocks without flagging that the orientation is property-driven. Developers ship one orientation; the design is occasionally requested in the other and re-implemented from scratch.

    Correct

    Document `orientation` as a first-class property (horizontal default, vertical opt-in). The keyboard model adapts: ArrowLeft / Right for horizontal, ArrowUp / Down for vertical, with Home / End working in both.

Both

Contracts

Non-negotiable contracts

  1. APGAPG: Radio Group pattern

    SegmentedControl uses `role="radiogroup"` for view-toggle semantics — exactly one option active at a time, exclusive choice. `role="tablist"` is reserved for content-switching tabs.

    A tablist styled as a segmented control for what is really a view-toggle breaks the SR contract — assistive tech announces the surface as a tab system and users expect keyboard semantics that do not apply.

Vocabulary drift

Apple HIG
Segmented Control
Canonical name match.
Material 3
Segmented Buttons
Polaris
ButtonGroup (segmented styling)
Carbon
Content Switcher
Designer

Common mistakes

Blocker

#segmented-no-roving-tabindex

Every segment has tabindex="0"

Problem

Tab cycles through every segment one by one. APG canonical for radiogroup is roving tabindex — only the currently-checked segment has `tabindex="0"`, others have `tabindex="-1"`. ArrowKeys navigate within the group.

Fix

Roving tabindex — only the checked segment is in the tab order. ArrowKeys move focus AND selection (per APG radiogroup auto-activation). Tab from the radiogroup moves to the next document focusable, not to the next segment.

Blocker

#segmented-color-only-selected

Selection differentiated by colour alone

Problem

Selected segment has a filled background; unselected segments have transparent background. The differentiator is colour. Colour-vision deficient users cannot distinguish; SR users get only the `aria-checked` cue.

Fix

Pair colour with non-colour cue: contrast-text foreground change (selected segment uses primary text colour vs muted; unselected uses muted), optional weight change, optional inline checkmark for icon-only-variant. Colour is reinforcement, not the sole signal.

Major

#segmented-as-tabs

Used as content-switching tabs

Problem

The control is used to switch between different content panels (a settings page with "Account / Billing / Notifications" sections). Semantically this is Tabs; the `role="radiogroup"` of SegmentedControl is wrong here — SR users hear "radio button" instead of "tab", and panel content does not get the `role="tabpanel"` relationship.

Fix

Use Tabs for content-switching. SegmentedControl is for view-of-same-content (list vs grid). The decision test: does activating a segment change *what content is shown* or *how the same content is displayed*? "What" → Tabs; "how" → SegmentedControl.

Major

#segmented-arrow-no-activate

ArrowKeys move focus but do not activate

Problem

Implementation copies the manual-activation pattern from Tabs. ArrowKeys move focus between segments; the user must press Enter / Space to activate. APG radiogroup canonical is auto-activation — ArrowKey IS the activation.

Fix

ArrowKey moves focus AND activates the new segment. `aria-checked` flips immediately. The indicator (if present) animates to the new position. Enter / Space are no-ops on the focused segment when it is already checked (or are equivalent to ArrowKey activation if a rare focus-without-check edge case exists).

Minor

#segmented-overflow-silent

Overflowing segments clipped at the inline-end

Problem

Five-segment control rendered in a narrow container; the last two segments clip at the edge. Users cannot see them; SR users navigate to them via ArrowKey but pointer users miss their existence.

Fix

For SegmentedControl above 5 segments, redesign as tabs with overflow-scroll, a Select, or splitting into smaller controls. Document the canonical maximum segment count in performance. Above the threshold, SegmentedControl is the wrong pattern.

Accessibility hints
Slot Accessibility hint
root Apply `role="radiogroup"` plus an `aria-label` (or `aria-labelledby` referencing a heading near the control). The radiogroup is the canonical APG choice because segments are *mutually-exclusive choices about view*, not navigation between content. Tabs would be wrong — Tabs switch content, segments switch view-of- content.
segment Each segment is `role="radio"` with `aria-checked` reflecting selection state. Roving tabindex — only the currently-checked segment has `tabindex="0"`, others have `tabindex="-1"`. Disabled segments use `aria-disabled` and stay focusable so SR users hear them.
icon Decorative when paired with a visible label (`aria-hidden="true"`). For icon-only variant, the segment's `aria-label` carries the meaning ("List view", "Grid view") because the icon alone is not a label.
label Plain text. When icon-only variant is used, the label is hidden visually but kept in the DOM (visually- hidden) for SR users — never replaced by `aria-label` without a visible alternative when the segment also renders text.
indicator Decorative — `aria-hidden="true"`. Selection is communicated through `aria-checked` on the radio segments; the indicator is visual reinforcement.