SegmentedControl
Compact row of mutually-exclusive options.
A compact, inline toggle for picking one of a few options (view, mode, locale). The selected segment is highlighted with a token-driven fill (zero radius), and the group behaves as a single radiogroup: one tab stop, arrow / Home / End keys move and select, disabled options are skipped.
Demo
Usage
<script>
import { SegmentedControl } from 'dssoca';
let view = $state('grid');
</script>
<SegmentedControl
label="View mode"
options={[
{ value: 'list', label: 'List', icon: 'logs' },
{ value: 'grid', label: 'Grid', icon: 'grid' },
{ value: 'map', label: 'Map' },
]}
bind:value={view}
/>WCAG 2.2 AA: `role="radiogroup"` with `role="radio"` segments, roving tabindex (one tab stop), and arrow / Home / End navigation that moves focus and selection together while skipping disabled segments. A `label` is required so the choice has an accessible name. For switching mutually-exclusive views/panels, a tablist/tab + tabpanel pattern is the alternative; this component implements the radiogroup pattern for value selection.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
options | SegmentOption[] | [] | Mutually-exclusive options: { value, label, icon?, disabled? }. |
value | string | — | Selected option value (bindable). |
label | string | — | Accessible name for the group (required → aria-label on the radiogroup). |
onChange | (value: string) => void | — | Fired when the selection changes, after `value` updates. |
fullWidth | boolean | false | Stretch segments to equal widths and fill the container. |
disabled | boolean | false | Disable the whole control: every segment is rendered inert (disabled, skipped by keyboard nav, no tab stop) and the group carries aria-disabled="true". Per-option `disabled` still disables individual segments. |
size | 'sm' | 'md' | 'lg' | — | Per-instance size override; inherits the ancestor `data-size-variant` when unset. |