Skip to content
Component installs need the registry setup— the Base UI shadcn project, the @vegastack namespace and the Cloudflare Access service token.
VegaStack Design

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
stable
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/segmented

Usage

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):

Segmented — data-slot="segmented"
SegmentedItem — data-slot="segmented-item"

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

ComponentSelection modelUse for
Segmentedexactly one, alwayspeer view/mode switches (table/board, monthly/annual, filter scopes)
Tabsexactly one, alwaysswapping content panels below the control
ToggleGroupzero-or-one / manyformatting toggles where empty or multiple selection is meaningful
Switchon/offa 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

PropTypeDefaultDescription
defaultValuestringfirst enabled itemThe 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).
valuestringThe selected segment's value. Controlled counterpart of defaultValue.

Data attributes and CSS variables on Segmented

AttributeValues
data-sizemirrors a prop or state value
data-slot"segmented"

SegmentedItem

PropTypeDefaultDescription
size"lg" | "md"inherited from SegmentedDensity override for a single chip.

Data attributes and CSS variables on SegmentedItem

AttributeValues
data-sizemirrors a prop or state value
data-slot"segmented-item"

Accessibility

  • Always pass aria-label (or aria-labelledby) on the root — the group needs a name.
  • Icon-only segments need their own aria-label.
  • Focus is the global 2px :focus-visible outline; the raised chip is not the only state signal (aria-pressed + border + text color change together).
KeyAction
Arrow Left / Arrow RightMove focus between enabled segments.
Space / EnterSelect the focused segment.
ContractStates tested
Behaviourdefault, active, disabled, empty, pressed, selected
Accessibilitylabeled, pressed
Visualdefault, hover, disabled, empty

Do / Don't

Do
Use Segmented for a short set of peer modes where one option must remain active.
Don't
Use it to switch content panels or for selections that may be empty or multiple.

On this page