vaiperui

components / segmented-control

SegmentedControl

A single choice among a few options, to switch between views of the same content.

How to use

Place `SegmentedItem`s inside a `SegmentedControl`. It is a `radiogroup`: one item is always selected, arrows move and select (skipping disabled items), and `aria-label` is required. Works controlled (`value`) or uncontrolled (`defaultValue`). For navigating between sections use `Tabs`.

preview
SegmentedControl.tsx
import { SegmentedControl, SegmentedItem } from "vaiperui";
<SegmentedControl aria-label="View" defaultValue="list">
<SegmentedItem value="list">List</SegmentedItem>
<SegmentedItem value="grid">Grid</SegmentedItem>
<SegmentedItem value="map">Map</SegmentedItem>
</SegmentedControl>

Colors

preview
primary
success
warning
danger
colors.tsx
<SegmentedControl aria-label="…" defaultValue="list" variantColor="primary">
<SegmentedItem value="list">List</SegmentedItem>
<SegmentedItem value="grid">Grid</SegmentedItem>
</SegmentedControl>
<SegmentedControl aria-label="…" defaultValue="list" variantColor="success">
<SegmentedItem value="list">List</SegmentedItem>
<SegmentedItem value="grid">Grid</SegmentedItem>
</SegmentedControl>
<SegmentedControl aria-label="…" defaultValue="list" variantColor="warning">
<SegmentedItem value="list">List</SegmentedItem>
<SegmentedItem value="grid">Grid</SegmentedItem>
</SegmentedControl>
<SegmentedControl aria-label="…" defaultValue="list" variantColor="danger">
<SegmentedItem value="list">List</SegmentedItem>
<SegmentedItem value="grid">Grid</SegmentedItem>
</SegmentedControl>

Sizes

preview
sm
md
lg
sizes.tsx
<SegmentedControl aria-label="…" defaultValue="list" size="sm">
<SegmentedItem value="list">List</SegmentedItem>
<SegmentedItem value="grid">Grid</SegmentedItem>
</SegmentedControl>
<SegmentedControl aria-label="…" defaultValue="list" size="md">
<SegmentedItem value="list">List</SegmentedItem>
<SegmentedItem value="grid">Grid</SegmentedItem>
</SegmentedControl>
<SegmentedControl aria-label="…" defaultValue="list" size="lg">
<SegmentedItem value="list">List</SegmentedItem>
<SegmentedItem value="grid">Grid</SegmentedItem>
</SegmentedControl>

Radius

preview
none
sm
md
lg
full
radius.tsx
<SegmentedControl aria-label="…" defaultValue="list" radius="none">
<SegmentedItem value="list">List</SegmentedItem>
<SegmentedItem value="grid">Grid</SegmentedItem>
</SegmentedControl>
<SegmentedControl aria-label="…" defaultValue="list" radius="sm">
<SegmentedItem value="list">List</SegmentedItem>
<SegmentedItem value="grid">Grid</SegmentedItem>
</SegmentedControl>
<SegmentedControl aria-label="…" defaultValue="list" radius="md">
<SegmentedItem value="list">List</SegmentedItem>
<SegmentedItem value="grid">Grid</SegmentedItem>
</SegmentedControl>
<SegmentedControl aria-label="…" defaultValue="list" radius="lg">
<SegmentedItem value="list">List</SegmentedItem>
<SegmentedItem value="grid">Grid</SegmentedItem>
</SegmentedControl>
<SegmentedControl aria-label="…" defaultValue="list" radius="full">
<SegmentedItem value="list">List</SegmentedItem>
<SegmentedItem value="grid">Grid</SegmentedItem>
</SegmentedControl>

Custom color

preview
Orange
Violet
custom-color.tsx
<SegmentedControl aria-label="…" defaultValue="list" customColor="#f97316">
<SegmentedItem value="list">List</SegmentedItem>
<SegmentedItem value="grid">Grid</SegmentedItem>
</SegmentedControl>
<SegmentedControl aria-label="…" defaultValue="list" customColor="#8b5cf6">
<SegmentedItem value="list">List</SegmentedItem>
<SegmentedItem value="grid">Grid</SegmentedItem>
</SegmentedControl>

States

preview
disabled
states.tsx
<SegmentedControl aria-label="…" disabled>…</SegmentedControl>

Props

PropValuesDefaultDescription
aria-labelstringrequiredNames what the control selects
valuestringnoneSelected item (controlled)
defaultValuestringnoneInitial item (uncontrolled)
onValueChange(value: string) => voidnoneCalled when the selection changes
disabledbooleanfalseDisables the whole control
variantColor / customColorControlColors | CustomColorneutralColor of the selected item's text; neutral when neither is set
sizesm | md | lgmdSize of the control and its text
radiusnone | sm | md | lg | fullmdCorner rounding
animationnone | smooth | fast | bouncesmoothTransition between states
SegmentedItem: value, disabledstring, booleannoneThe item's value; disables only this item

Accessibility

  • The container has `role="radiogroup"`, and `aria-disabled` when the whole control is `disabled`.
  • Each `SegmentedItem` is a button with `role="radio"` and `aria-checked`.
  • Roving tabindex: only the selected item is in the Tab order (`tabIndex=0`).
  • Arrow keys move focus and select at once, wrap around, and skip disabled items.

Keyboard

KeyAction
TabMoves focus into and out of the group (to the selected item).
Right / DownSelects the next enabled item.
Left / UpSelects the previous enabled item.
Enter / SpaceSelects the focused item (native button click).

Keep in mind

  • Pass an `aria-label` or `aria-labelledby` on `SegmentedControl`; the component does not add a name to the group.
  • Pass `value` or `defaultValue`; with no selected item every item has `tabIndex=-1` and the group is unreachable by keyboard.
  • Home and End are not handled.