# Segmented control

A segmented control switches between views or modes of the same thing, like Price and Demand on a chart, grid and list, or light and dark.

## When to use

- To switch how the same content is shown, like a chart's price basis or time range.
- To pick between two to five short, related options where all of them should stay visible.
- To filter one list by a mode, like *Mine* and *All*.

## When not to use

- When each option opens different content, like a page's Overview and Activity, use tabs.
- To turn one setting on or off, use a switch.
- For more than five options, or labels that don't fit on one line, use a select or a radio group.
- To start an action, use buttons.

## Anatomy

## Sizes

- **md** (40px) is the default, for controls that stand on their own, like a dialog's Deposit and Withdraw.
- **sm** (32px) sits in dense headers and toolbars, like chart controls and table filters.

Each size takes text or icons. Icons are 20px at md and 16px at sm.

## States

- **Selected** sits on a lighter pill with a small shadow and full-strength text. One option is always selected.
- **Unselected** options use muted text, and turn full strength on hover.
- **Disabled** drops to 40% opacity. Disable the whole control, or a single option that doesn't apply right now.

## Full width

Set `fullWidth` to split the width evenly between the options, for example across the top of a dialog. Otherwise each option is as wide as its label.

## Narrow space

When the options are wider than the space, the track scrolls sideways instead of wrapping. The scrollbar stays hidden, the edge with more options fades out, and picking an option scrolls it fully into view. Keep labels short so most screens show every option without scrolling.

## Content

- Name each view with a short noun, like *Price*, *Bids* or *1W*. One or two words.
- Use sentence case and no full stop.
- Keep every option the same kind: all text or all icons. Icon-only options need an `ariaLabel`.
- A segmented control never wraps. On a narrow screen it scrolls sideways and fades the edge that has more options, so keep labels short enough that most screens show them all.

## Behaviour

| Key | Action |
| --- | --- |
| <kbd>Tab</kbd> | Moves focus to the selected option. The control is one tab stop. |
| <kbd>←</kbd> <kbd>→</kbd> (or <kbd>↑</kbd> <kbd>↓</kbd>) | Selects the previous or next option, wrapping at the ends. |
| <kbd>Home</kbd> / <kbd>End</kbd> | Selects the first or last option. |

Clicking an option selects it. The pill glides to the new option with a small spring, and the label turns full strength as the pill covers it. Arrow keys move the pill straight to the next option without gliding, so fast keyboard use never lags, and they skip disabled options. Under reduced motion the pill never glides. When the options are wider than the space, the track scrolls sideways and keeps the selected option in view.

Selection happens on focus, so the view should change at once. If switching loads slowly, show the loading state inside the view, not on the control.

## Accessibility

- The control is a `radiogroup` of `radio` buttons with `aria-checked`, using a roving tab index.
- Give it a `label`, which becomes the group's `aria-label`, like *Chart scale*.
- Icon-only options need an `ariaLabel` each.
- Keyboard focus shows a 2px ring with a 2px gap (`focus/ring`), the same as the button.
- The selected option sits on its own pill, so it doesn't rely on text colour alone.

## Props

| Prop | Type | Default | Notes |
| --- | --- | --- | --- |
| `options` | `{ value, label?, icon?, ariaLabel?, disabled? }[]` | Required | Two to five options. |
| `value` | `string` | Required | The selected option's value. |
| `onValueChange` | `(value) => void` | Required | Called with the new value. |
| `label` | `string` | Required | Names the group for screen readers. |
| `size` | `"md" \| "sm"` | `"md"` | 40px or 32px tall. |
| `fullWidth` | `boolean` | `false` | Fills the container and splits it evenly. |
| `disabled` | `boolean` | `false` | Dims the whole control and takes it out of the tab order. |
| `className` | `string` | | Added to the track. |

## Related

- A [Switch](/components/switch/) turns one setting on or off.
- Tabs switch between different content, not views of the same content.
