Controlsregistry/ui/segmented-control.tsx/r/segmented-control.json

SegmentedControl

Exposure-sheet cell selector with a mix-blend-mode: difference indicator that steps across cells in 3 held poses.

Light · Paper.f12-theme-light
Interactive preview
Selected: 7 days
Dark · Flashback.f12-theme-dark
Interactive preview
Selected: 7 days

Install & copy-in source

shadcn CLI (segmented-control.json)
npx shadcn@latest add https://frame12.dev/r/segmented-control.json
Usage example (SegmentedControl)
import { SegmentedControl } from '@/components/frame12';

export function RangeSelector({ range, setRange }: { range: number; setRange: (r: number) => void }) {
  return (
    <SegmentedControl
      ariaLabel="Date range"
      options={[
        { value: 7, label: '7', unit: 'days' },
        { value: 30, label: '30', unit: 'days' },
        { value: 90, label: '90', unit: 'days' },
      ]}
      value={range}
      onChange={setRange}
    />
  );
}
WCAG AAAccessibility guarantees

Accessibility notes

  • Uses role="group" with aria-pressed={active} on native <button type="button"> elements.
  • Provides a 3px solid --f-marker inset focus ring on :focus-visible.
GrammarFRAME/12 rules

Design grammar

  • In .f12-m-stepped mode, the indicator transitions with steps(3, end) over 250ms (3 held poses at 83.33ms).
  • Uses mix-blend-mode: difference so text covered by the indicator remains legible at every intermediate pose.

Props & TypeScript API

Exported from @/components/frame12 (registry/ui/segmented-control.tsx)
PropTypeDefaultDescription
optionsArray<{ value: T; label: string; unit?: string }>requiredOrdered cell options with display numeral/label and optional mono unit.
valueTrequiredCurrently active option value.
onChange(value: T) => voidrequiredCallback fired when a cell is activated.
ariaLabelstring'Options'Accessible label for the role="group" container.
idPrefixstring'seg'Prefix for deterministic button IDs (${idPrefix}-${opt.value}).