SegmentedControl
A few mutually exclusive choices, all visible at once.
import { ... } from '@corndev/ui' Body: json
HTML
<div class="corn-segmented" role="radiogroup" aria-label="Body type" data-size="md">
<label class="corn-segmented-option">
<input class="corn-segmented-input" type="radio" name="body" value="none" />
<span class="corn-segmented-label">none</span>
</label>
<label class="corn-segmented-option">
<input class="corn-segmented-input" type="radio" name="body" value="json" checked />
<span class="corn-segmented-label">json</span>
</label>
<label class="corn-segmented-option">
<input class="corn-segmented-input" type="radio" name="body" value="form" />
<span class="corn-segmented-label">form</span>
</label>
</div>
Classes
| Class |
|---|
.corn-segmented |
.corn-segmented-option |
.corn-segmented-input |
.corn-segmented-label |
Attributes
| Attribute | Values |
|---|---|
data-size | sm|md|lg |
data-full-width | present or absent |
Vanilla JS
Required for behaviour — adds builds the options from data and reports changes with each option’s own value; written out as markup, the radios need no JavaScript.
import { createSegmentedControl } from '@corndev/ui';
import '@corndev/ui/theme';
const el = document.querySelector('#target');
const instance = createSegmentedControl(el, { /* options */ });
Options
| Option | Type | Default | Description |
|---|---|---|---|
options | Array<SegmentedOption|string|number> | required | The choices: strings, numbers (a number is handed back as a number), or { label, value, disabled } — the same shapes as Combobox and SearchBar. |
value | * | undefined | The chosen value. Pass it to update() to drive the control from outside. |
defaultValue | * | undefined | Initially chosen. Defaults to the first option. |
onChange | (value: *) => void | undefined | Called with the newly chosen value. |
size | 'sm'|'md'|'lg' | 'md' | |
disabled | boolean | false | Disables every option. |
fullWidth | boolean | false | Stretch to the container, options sharing it equally. Otherwise as wide as its options. |
name | string | undefined | The radios’ name, for a form. Generated if not given. |
React
SegmentedControl — from @corndev/ui-react.
The props are the same as the options above, plus className.
For a handful of choices — two to five, a word or two each — that sit above the
thing they switch: a request body’s type, a schema’s allOf / oneOf / anyOf, a
response pane’s pretty / raw / preview. A dropdown would hide the options, and a
column of radios would take most of the panel. Seeing the alternatives is the
point.
<SegmentedControl
aria-label="Request body"
options={['none', 'json', 'form']}
value={body}
onChange={setBody}
/>
options takes strings, numbers, or { label, value, disabled } — the same shapes
as Combobox and SearchBar, so a control can move between them without reshaping
its data. A number comes back as a number.
It is a radio group
Each option is a real radio input, visually hidden. That is what makes it behave like one:
- the arrow keys move the selection
- the whole control is one tab stop
- a screen reader announces “json, radio, 2 of 3” — one choice among several
A row of buttons with aria-pressed looks the same and says something different:
“these toggles happen to exclude each other”, which someone using a screen reader
then has to find out by trying them.
The chosen option is marked by a raised surface, a border and a heavier weight, not colour alone, and every option is at least a 24 × 24 target at every size.
Without JavaScript
Written out as markup, it needs no script at all — the radios do their own keyboard work:
<div class="corn-segmented" role="radiogroup" aria-label="Body type" data-size="md">
<label class="corn-segmented-option">
<input class="corn-segmented-input" type="radio" name="body" value="none" />
<span class="corn-segmented-label">none</span>
</label>
<label class="corn-segmented-option">
<input class="corn-segmented-input" type="radio" name="body" value="json" checked />
<span class="corn-segmented-label">json</span>
</label>
</div>
createSegmentedControl(el, { options, onChange }) builds the same thing from data.
Options
size—sm,mdorlgfullWidth— stretch to the container, the options sharing it equally. Otherwise it is as wide as its options.disabledon the control disables every option;{ disabled: true }on one option disables just that one.