Segmented
A single-select, always-one-selected view/mode switcher — a bounded muted track with a raised active chip. The canonical segmented-control formula.
- Status
- Since
0.3.0- Accessibility pattern
- APG toolbar of toggle buttons
Last updated
Install
Add Segmented from the VegaStack registry. The CLI verifies the item's integrity hash before writing it.
pnpm dlx shadcn@latest add @vegastack/segmentedUsage
import { Segmented, SegmentedItem } from "@/components/ui/segmented";
<Segmented defaultValue="monthly" aria-label="Billing cycle">
<SegmentedItem value="monthly">Monthly</SegmentedItem>
<SegmentedItem value="annual">Annual</SegmentedItem>
</Segmented>;Anatomy
Segmented is a compound component. Every exported part, with the
data-slot it renders (generated from the canonical source):
Examples
Controlled
value/onValueChange use plain strings (not arrays — this is not a ToggleGroup). The
callback never fires with "nothing selected": clicking the active segment is a no-op.
Scope: all — clicking the active segment is a no-op (always-one-selected).
When to use which
| Component | Selection model | Use for |
|---|---|---|
Segmented | exactly one, always | peer view/mode switches (table/board, monthly/annual, filter scopes) |
Tabs | exactly one, always | swapping content panels below the control |
ToggleGroup | zero-or-one / many | formatting toggles where empty or multiple selection is meaningful |
Switch | on/off | a single boolean |
Anatomy & geometry
The track and chip are the system's one selected-chip recipe (selectedChipVariants), shared with
Tabs pill/chip and pressed Toggle/ToggleGroup so the four cannot drift apart: the track is
rounded-md p-0.5 on the ladder's well rung with a visible border-border boundary, and the chip
is rounded-sm on the pressed/selected rung with its own hairline — the nested-radius formula
(container radius minus padding). The
selected chip is not exempt from interaction: hovering it strengthens the tint and pressing it drops
back to the resting tint, previewing the release. Sizes:
default (24px chips in a 28px track — dense chrome) and lg (28px chips — form rows).
Keyboard: arrow keys move focus, Space/Enter selects (Base UI Toggle Group contract);
aria-pressed marks the active segment.
API Reference
Segmented
| Prop | Type | Default | Description |
|---|---|---|---|
defaultValue | string | first enabled item | The initially selected segment's value. Defaults to the first enabled direct item. |
onValueChange | ((value: string) => void) | — | Fired with the newly selected segment value. Never fires with "nothing selected". |
size | "lg" | "md" | 'md' | Track density — md (24px chips in a 28px track, chrome scale) or
lg (28px chips, form-row scale). |
value | string | — | The selected segment's value. Controlled counterpart of defaultValue. |
Data attributes and CSS variables on Segmented
| Attribute | Values |
|---|---|
data-size | mirrors a prop or state value |
data-slot | "segmented" |
SegmentedItem
| Prop | Type | Default | Description |
|---|---|---|---|
size | "lg" | "md" | inherited from Segmented | Density override for a single chip. |
Data attributes and CSS variables on SegmentedItem
| Attribute | Values |
|---|---|
data-size | mirrors a prop or state value |
data-slot | "segmented-item" |
Accessibility
- Always pass
aria-label(oraria-labelledby) on the root — the group needs a name. - Icon-only segments need their own
aria-label. - Focus is the global 2px
:focus-visibleoutline; the raised chip is not the only state signal (aria-pressed+ border + text color change together).
| Key | Action |
|---|---|
| Arrow Left / Arrow Right | Move focus between enabled segments. |
| Space / Enter | Select the focused segment. |
| Contract | States tested |
|---|---|
| Behaviour | default, active, disabled, empty, pressed, selected |
| Accessibility | labeled, pressed |
| Visual | default, hover, disabled, empty |
Do / Don't
Toggle Group
A set of joined toggle buttons sharing one selection — single or multiple selection, three sizes, horizontal or vertical layout, full keyboard navigation.
Input
A styled Base UI input — all input types, Field state data attributes, error and disabled states, focus border recolor, and optional prefix/suffix addons.