Tessera UI

SegmentedControl

A radio-group style control where one segment is selected at a time, with outline, filled, and pill variants, horizontal and vertical orientations, and full keyboard navigation

Installation

pnpm add @tessinaui/ui

Usage

import { SegmentedControl, SegmentedControlItem } from "@tessinaui/ui";
<SegmentedControl defaultValue="week">
  <SegmentedControlItem value="day"   label="Day" />
  <SegmentedControlItem value="week"  label="Week" />
  <SegmentedControlItem value="month" label="Month" />
</SegmentedControl>

Playground

Configure every property of the SegmentedControl component interactively:

Preview
Loading...

Showcase

All variants, sizes, orientations, icon combinations, and states:

Preview
Loading...

API Reference

SegmentedControl Props

PropTypeDefaultDescription
valuestringControlled selected value
defaultValuestringInitial selected value for uncontrolled usage
onValueChange(value: string) => voidCallback fired when selection changes
variant"outline" | "filled" | "pill""outline"Visual style
size"xs" | "sm" | "md" | "lg""md"Size applied to all items
orientation"horizontal" | "vertical""horizontal"Layout direction
disabledbooleanfalseDisables all items in the group
dir"ltr" | "rtl""ltr"Text direction — RTL reverses layout

SegmentedControlItem Props

PropTypeDefaultDescription
valuestringrequiredUnique value identifying this item
labelstringVisible label text
leadingIconReact.ReactNodeIcon rendered before the label
disabledbooleanfalseDisables this item individually
aria-labelstringAccessible label (required when no visible label is provided)

Variants

VariantUnselectedSelected
outlineBorder + transparent backgroundWhite background, no border, subtle shadow
filledTransparent, muted textPrimary brand fill + on-primary text
pillTransparent, default textPrimary brand fill + on-primary text

Sizes

SizeWrapper heightUse case
xs40pxCompact toolbars
sm48pxSecondary controls
md52pxDefault, most use cases
lg52pxProminent controls with larger text

Controlled vs Uncontrolled

Controlled — manage selection state externally:

const [view, setView] = useState("week");

<SegmentedControl value={view} onValueChange={setView}>
  <SegmentedControlItem value="day"   label="Day" />
  <SegmentedControlItem value="week"  label="Week" />
  <SegmentedControlItem value="month" label="Month" />
</SegmentedControl>

Uncontrolled — let the component manage its own state:

<SegmentedControl defaultValue="week">
  <SegmentedControlItem value="day"   label="Day" />
  <SegmentedControlItem value="week"  label="Week" />
  <SegmentedControlItem value="month" label="Month" />
</SegmentedControl>

Accessibility

The SegmentedControl component:

  • Renders with role="radiogroup" on the wrapper for semantic grouping
  • Each item renders with role="radio" and aria-checked reflecting selection state
  • Keyboard navigation: Arrow keys move between items (Left/Right for horizontal, Up/Down for vertical); Home/End jump to first/last
  • Roving tabIndex: only the selected item (or first enabled item if none selected) is in the tab order
  • Disabled items are skipped during keyboard navigation
  • Touch targets ≥ 44×44px on all sizes
  • aria-label required on icon-only SegmentedControlItem elements
  • RTL fully supported via the dir prop

On this page