EDS 0.x
Components

Segmented Control

Examples

Default

Exclusive selection in a compact track. Defaults to Sm (36px) — the Figma default size set.

Sizes

Figma size sets: Sm 36px (default) · Md 40px · Lg 44px.

Icons

Icon-only and text+icon segments. Icon-only items require aria-label.

Fluid

fluid stretches the control and gives segments equal width.

Disabled

Disable the whole control or individual segments.

TanStack Form

Bind with value / onValueChange / name — no adapters.

View

RTL

Layout uses logical properties — segment order and icon placement follow dir.

API Reference

Segmented

PropTypeDefaultDescription
itemsSegmentedItem[]Segments to render
size"sm" | "md" | "lg""sm"Track height 36 / 40 / 44
fluidbooleanfalseEqual-width segments that fill the control
valuestringControlled selected value
defaultValuestringfirst itemUncontrolled initial value
onValueChange(value: string, eventDetails) => voidFires when selection changes (never empty)
disabledbooleanfalseDisables the whole control
namestringHidden input name for native form posts
classNamestringExtra classes on the track
idstringTrack id
aria-labelstringAccessible name for the group
aria-labelledbystringId of a visible label
aria-describedbystringId of description / error text

SegmentedItem

PropTypeDefaultDescription
valuestringUnique value within the control
labelReactNodeSegment text (omit for icon-only)
iconReactNodeInline-start icon
disabledbooleanfalseDisables this segment only
aria-labelstringRequired for icon-only segments

Dropdown segments (SegCtrl → Dropdown in Figma) are out of scope for this release.

Accessibility

WCAG success criteria

CriterionLevelHow EDS helps
2.1.1 KeyboardAFull keyboard selection via Tab, arrows, Space/Enter
2.4.7 Focus VisibleAADistinct focus-visible ring on segments
4.1.2 Name, Role, ValueAGroup naming + aria-pressed value; icon-only names via item aria-label
1.3.1 Info and RelationshipsAGroup/label association through aria-labelledby / aria-label
1.4.3 Contrast (Minimum)AAText and icons use semantic foreground tokens against track/selected surfaces
1.4.11 Non-text ContrastAASelected border, focus ring, and control boundary use outline/adaptive tokens

Why it matters

Segmented controls look like tabs but behave like an exclusive choice — the wrong pattern leaves keyboard and screen-reader users guessing whether they can leave a view empty, how focus moves, and what each icon means. A clear group name, pressed state, and arrow-key navigation keep dense filters and view switchers usable for everyone, including motor and cognitive impairments.

Keyboard

KeyBehavior
⇥ Tab / + ⇥ TabMoves focus into / out of the control (roving tabindex among segments)
/ Moves focus between segments (respects dir; loops at the ends)
/ Same as horizontal arrows for this control
Space / ↵ EnterSelects the focused segment
Clicking the active segmentSelection is not cleared — one option always remains selected

Disabled segments are skipped for activation. A fully disabled control is removed from the tab order as a group of disabled buttons.

Screen readers & semantics

Built on Base UI Toggle Group:

SurfaceImplementation
Grouprole="group" — set aria-label or aria-labelledby on Segmented
SegmentNative <button> with aria-pressed for the selected state
Icon-onlyPass aria-label on the item; icon markup is aria-hidden
Form nameOptional hidden <input type="hidden"> mirrors the selected value

Do not nest another interactive control inside a segment label. Prefer a visible <label id> + aria-labelledby over a redundant aria-label when the page already shows a heading for the control.

Focus & visuals

ConcernEDS behavior
Focus ring2px outline-primary inset on the focused segment (Figma Focus)
Selectedbg-secondary + adaptive-20 border + shadow-xs lift
Hoverbg-tertiary-hover on unselected segments
Disabledtext-disabled; selected+disabled keeps the lift at reduced opacity
RTLLogical padding/gap; DOM order + dir drive reading and arrow keys
ContrastToken-mapped track (adaptive-8) and selected surface (bg-secondary)

Build with it

DoDon’t
Give the control an aria-label or aria-labelledbyShip an unlabeled group of identical “Label” buttons
Set aria-label on every icon-only itemRely on decorative SVG alone for the accessible name
Use for exclusive, same-level choices (views, ranges)Use as navigation tabs that change URL without selection semantics
Bind value / onValueChange for TanStack FormInvent a wrapper that remaps pressed arrays
Disable a segment when the option is unavailableHide the only remaining valid option and leave selection empty

Quick test

  1. Keyboard — Tab to the control, arrow across segments, confirm Space/Enter selects and the previous segment unpresses. Click the active segment and confirm it stays selected.
  2. Screen reader — With VoiceOver/NVDA, verify the group name and that the selected segment announces as pressed.
  3. Icon-only — Navigate an icon-only control and confirm each segment has a spoken name.
  4. RTL — Open the RTL example; confirm order, icons, and arrow keys follow dir="rtl".
  5. Form — Submit the TanStack Form demo empty (error), then with a selection (success).

On this page