@akhatmirzo/ui

SegmentedControl

Pick one of a few options — a sliding indicator, icons and the same sizes as Button.

Import

import { SegmentedControl } from '@akhatmirzo/ui';

When to use

  • View modes — "Grid / List / Map". The choice applies immediately.
  • Filters or periods — "Day / Week / Month", "All / Paid / Unpaid".
  • Keep it to 2–5 short options. For more or longer ones use a Select or a RadioGroup.
  • Not for on/off — a two-state setting is a Switch.

How it differs from Tabs

They can look the same, but they do different jobs:

TabsSegmentedControl
What it doesSwitches content panelsPicks a value (filter, mode, period)
Semanticstablist / tab / tabpanelradiogroup / radio
ResultA different section of the page showsThe same content is refiltered or redrawn
FormsNoSubmits a value with name

Rule of thumb: if the choice reveals different content, use Tabs; if the same content changes how it looks or what it shows, use SegmentedControl.

Sizes

size — sm (32px), md (40px, default), lg (48px). The heights match Button and Input, so they line up in one row.

Icons

icon adds an icon before the text. Icon-only items require an aria-label — TypeScript enforces it.

Full width

fullWidth fills the container and splits it evenly between items. Handy in mobile forms.

Controlled

value + onValueChange — you keep the selection. Clicking the selected item again doesn't clear it: one value is always selected.

Savdo: 8 740 000 so'm

Disabled

Pass disabled to the whole group or to a single SegmentedControl.Item. Disabled items can't be clicked and the keyboard skips them.

Props

SegmentedControl

Other <div> attributes and Radix RadioGroup props (name, required, loop, dir) are passed through; ref points to the root element.

PropTypeDefaultDescription
valuestring—Selected value (controlled mode)
defaultValuestring—Initial value
onValueChange(value: string) => void—When the selection changes
size'sm' | 'md' | 'lg''md'Height: 32 / 40 / 48px
fullWidthbooleanfalseFills the width, items share it evenly
disabledboolean—Disables the whole group
namestring—For forms (hidden radio input)
aria-labelstring—Group name (e.g. Period or View)

SegmentedControl.Item

PropTypeDefaultDescription
valuerequiredstring—Item value
iconReactNode—Icon before the text
disabledboolean—Disables the item
aria-labelstring—Required for icon-only items

Data attributes

AttributeWhereValue
data-sizerootsm · md · lg
data-full-widthrootpresent with fullWidth
data-disabledroot, itempresent when disabled
data-stateitemchecked · unchecked
data-slotindicatorsegmented-control-indicator

Keyboard

KeyAction
TabEnter the group (on the selected item) and leave it
← ↑ / → ↓Previous / next item — selected as soon as it gets focus

Accessibility

  • Roles. The root is role="radiogroup", each item role="radio" (aria-checked). Built on Radix RadioGroup: single selection with roving focus — the group is one Tab stop.
  • Name. Give the group an aria-label ("Period"). Inside a Field the label names the group and the description is linked through aria-describedby.
  • Icon-only items need an aria-label (checked by TypeScript).
  • The indicator is decorative — aria-hidden. It measures the selected item and slides over 200ms; it re-measures when sizes change (window width, font loading). With prefers-reduced-motion it jumps without animating.

On this page