{
  "title": "SegmentedControl",
  "description": "Single-select switcher styled as a row of segments inside a single rounded container.",
  "url": "/docs/components/segmented-control",
  "since": "0.2.0",
  "tags": [
    "control",
    "form"
  ],
  "platform": "both",
  "source": "---\ntitle: SegmentedControl\ndescription: Single-select switcher styled as a row of segments inside a single rounded container.\nsince: 0.2.0\ntags: [control, form]\nplatform: both\ncategory: controls\n---\n\nimport { BundleSize } from '@/components/bundle-size';\nimport { Preview } from '@/components/preview';\nimport { PropsTable } from '@/components/props-table';\n\n<BundleSize component=\"SegmentedControl\" />\n\n## At a glance\n\n- Compact \"iOS UISegmentedControl\" pattern — a row of segments inside a single rounded container, only one selected.\n- Use for binary or small (3–5) inline choices that sit next to their content. Reach for [Tabs](/docs/components/tabs) when each option owns a distinct content region.\n- Keyboard nav follows the WAI-ARIA radiogroup pattern: arrow keys move between segments (selection follows focus), `Home` / `End` jump to first / last, with wrap-around. Disabled segments are skipped.\n- Always exactly one selection. If \"no selection\" is a valid state, use [`Toggle.Group`](/docs/components/toggle#togglegroup) with `type=\"single\"` instead.\n\n## Preview\n\n<Preview name=\"segmented-control-basic\" />\n\n## `options`\n\nArray of segment descriptors. Each option has at least `value` and\n`label`; pass `disabled: true` to skip an option (it's still rendered,\ngreyed out, and skipped by arrow-key navigation).\n\n```tsx\n<SegmentedControl\n    label=\"View\"\n    defaultValue=\"grid\"\n    options={[\n        { value: 'grid', label: 'Grid' },\n        { value: 'list', label: 'List' },\n        { value: 'map', label: 'Map', disabled: true },\n    ]}\n/>\n```\n\n## `value` and `defaultValue`\n\nControlled via `value` (paired with `onChange`); uncontrolled via\n`defaultValue`. The Segmented Control never falls back to \"no\nselection\" — the initial value must match one of the option `value`s.\n\n```tsx\nconst [view, setView] = useState<'grid' | 'list'>('grid');\n<SegmentedControl value={view} onChange={setView} options={…} />\n```\n\n## `onChange`\n\nFires with the next `value` whenever the user picks a segment. Pair\nwith `value` for controlled, omit for uncontrolled — the control\ncalls it either way.\n\n## `size`\n\nDensity. Aligned with Button / Toggle.\n\n| Value             | Min height |\n|-------------------|------------|\n| `sm`              | 32 px      |\n| `md` (default)    | 36 px      |\n| `lg`              | 44 px      |\n\n```tsx\n<SegmentedControl size=\"sm\" options={…} />\n```\n\n## `disabled`\n\nDisables every segment in the control. Individual segments can also\nopt out via `disabled` on the option.\n\n```tsx\n<SegmentedControl disabled defaultValue=\"grid\" options={…} />\n```\n\n## `label`\n\nAccessible name for the control. Required for screen readers — it's\nforwarded to the `radiogroup` / `group` ARIA role and announced when\nfocus enters the control.\n\n```tsx\n<SegmentedControl label=\"View mode\" options={…} />\n```\n\n## Props\n\n<PropsTable component=\"SegmentedControl\" />\n"
}
