Skip to main content

SegmentedControl

A compact, equal-width control for switching between 2-4 mutually exclusive options. Inspired by iOS UISegmentedControl — ideal for view toggles, filter sets, and grouped selectors where Radio would feel too loose and Tabs too heavy.

Basic Usage

Sizes

Disabled segment

Individual options can be disabled via option.disabled. The whole control is implicitly disabled when only one option is selectable.

When to use which

ComponentBest for
SegmentedControl2-4 mutually exclusive options of similar weight (view toggles, filter sets)
Tabs (variant="segmented")Same look, but bound to content panels via Tabs.Content
RadioGroup5+ options, or when labels need different lengths
Select (mobileVariant="sheet")Many options, or options the user picks once and rarely changes

The sliding indicator animation uses Pattern D (--tui-duration-base × --tui-ease-in-out) so the highlight glides between segments rather than snapping.

Mobile considerations

  • All segments meet the 44px tap target on both sm and md sizes (height scales up on pointer:coarse).
  • The indicator slide animation is GPU-accelerated (transform), so it stays smooth even on mid-range Android.
  • For 5+ options, switch to <Select mobileVariant="sheet"> — SegmentedControl wraps awkwardly on narrow viewports.

Props

PropTypeDefaultDescription
value*string-Currently selected option value (controlled)
onChange*(value: string) => void-Called when the user selects a different segment
options*SegmentedControlOption[]-{ value, label, disabled? } — 2-4 recommended
size'sm' | 'md''sm'Visual size
aria-labelstring-Accessible label for the segmented group
classNamestring-Additional CSS class for the track element
styleCSSProperties-Additional inline styles