ui · Primitive
SegmentedControl
@devalok/shilp-sutra/ui/segmented-controlView in Storybook Hand-curated previews ship in rolling waves. See it live in Storybook →
Reference
Props
size: "sm" | "md" | "lg"
variant: "default" | "solid"
options: SegmentedControlOption[] (REQUIRED)
selectedId: string (REQUIRED)
onSelect: (id: string) => void (REQUIRED)
disabled: boolean
Types
SegmentedControlOption = { id: string, text: string, icon?: ComponentType<{ className?: string }> }
SegmentedControlSize = 'sm' | 'md' | 'lg'
SegmentedControlVariant = 'default' | 'solid'
Defaults
size: "md"
variant: "default"
Example
<SegmentedControl
size="md"
variant="default"
options={[
{ id: 'list', text: 'List' },
{ id: 'grid', text: 'Grid' },
]}
selectedId={viewMode}
onSelect={setViewMode}
/>
Composability
- Data-driven, not compound — unlike Tabs/ToggleGroup, SegmentedControl takes an
optionsarray rather than children. This makes it easier to render from a list but harder to customize per-option styling; use Tabs if you need compound children. - When to use vs Tabs: SegmentedControl is for mutually-exclusive VIEW-MODE toggles (List/Grid/Kanban) — short labels, no associated content panel. Tabs is for content switching where each tab has a corresponding TabsContent. Both render
role="tablist". - Option icons auto-size based on the
sizeprop — don't set explicit icon sizes. - Fully controlled — there's no
defaultSelectedId. Manage state in parent. - Built from scratch (no Radix primitive) — standard HTML buttons with
aria-selectedand roving tabindex.
Gotchas
- Controlled only — selectedId + onSelect are required
- Uses data-driven API (options prop), not compound children
- Use Tabs (not SegmentedControl) when you need associated content panels per option
Changes
v0.38.0
- Removed (BREAKING) deprecated
variant="accent"alias. Usevariant="solid".
v0.18.0
- Fixed
bg-interactivechanged tobg-accent-9,bg-fieldchanged tobg-surface-3(OKLCH migration)
v0.4.2
- Changed (BREAKING)
colorprop renamed tovariant
v0.1.1
- Fixed
tabIndex={0}changed totabIndex={-1}on tablist wrapper — fixes double-focus keyboard navigation bug - Fixed Removed
!importantoverride — resolved specificity by restructuring base CVA classes
v0.1.0
- Added Initial release