SegmentedControl
Two to five mutually exclusive views or modes in one compact bar. Hidden native radios, so it works without JavaScript.
Examples
Links (URL-driven)
When every option has an href it renders a <nav> of links; the `value` option gets aria-current="page".
Light
Dark
<SegmentedControl
label="Harness"
value={harness}
options={harnesses.map((h) => ({ value: h.id, label: h.label, href: routes.dashboard.connect.href(undefined, { harness: h.id }) }))}
/>Text and icons
<SegmentedControl
name="transport"
label="Transport"
value="http"
options={[{ value: 'http', label: 'HTTP' }, { value: 'sse', label: 'SSE' }]}
/>
<SegmentedControl
name="format"
label="Config format"
size="sm"
options={[
{ value: 'json', label: 'JSON', icon: 'settings' },
{ value: 'cli', label: 'CLI', icon: 'terminal' },
]}
/>
<SegmentedControl
name="view"
label="View"
value="list"
options={[
{ value: 'list', label: 'List', icon: 'menu', iconOnly: true },
{ value: 'grid', label: 'Grid', icon: 'layers', iconOnly: true },
]}
/>Block
Fills the container, segments share the width.
<SegmentedControl
name="auth"
label="Authentication"
block
value="bearer"
options={[
{ value: 'oauth', label: 'OAuth' },
{ value: 'bearer', label: 'Bearer token' },
{ value: 'none', label: 'None' },
]}
/>Usage
import { SegmentedControl } from '@switchboard/ui'
<SegmentedControl name="transport" label="Transport" value={server.transport} options={transports} />Props
Every component also takes mix, for css() and mixins applied after its own style.
SegmentedControl
| Prop | Type | Default | Description |
|---|---|---|---|
| name* | string | – | Radio name; posts the checked value. Must be unique on the page. |
| label* | string | – | Accessible group name (aria-label). There is no visible legend. |
| options* | SegmentOption[] | – | { value, label, icon?, iconOnly?, disabled? }. iconOnly keeps label as the name and tooltip. |
| value | string | – | Checked value. Defaults to the first option. |
| size | 'sm' | 'md' | 'md' | Height 28 or 32px. |
| block | boolean | – | Stretch to the container width. |
| disabled | boolean | – | Disables every segment. |
Also accepts every <div> attribute.
Accessibility
- Each segment is a visually hidden native radio inside a <label>: one tab stop, arrow keys change the value, posts without JavaScript.
- The group has role="radiogroup" and aria-label from label; icon-only segments are named by their label.
- The checked segment is raised and its text darkens, so the state is not shown by colour alone.
Guidance
Do
- Use for switching a view or a mode with two to five short options.
- Keep labels to one or two words.
Don’t
- Use it for navigation between pages; use LinkTabs.
- Mix icon-only and text segments in one control.