SegmentedControl
A segmented control shows every option at once and keeps exactly one of them chosen. It suits a small, stable set — a date range, a view mode — where seeing the alternatives is worth the room they take. More than about five, or a set that changes, wants a Select.
import { SegmentedControl, SegmentedControlIndicator, SegmentedControlItem } from "ropav";Each SegmentedControlItem takes an id, which is what the selection reports. SegmentedControlIndicator is the sliding highlight behind the chosen segment.
<SegmentedControl aria-label="Reporting range" default-selected-key="weekly">
<SegmentedControlItem id="daily">
Daily
<SegmentedControlIndicator />
</SegmentedControlItem>
<SegmentedControlItem id="weekly">
Weekly
<SegmentedControlIndicator />
</SegmentedControlItem>
<SegmentedControlItem id="monthly">
Monthly
<SegmentedControlIndicator />
</SegmentedControlItem>
</SegmentedControl>The id deliberately does not reach the DOM as an id attribute — it surfaces as data-key instead, so two controls that both have a weekly segment cannot collide.
Choosing and disabling
default-selected-key starts the control somewhere; without one it falls back to the first segment that is not disabled, so a segmented control is never in a state with nothing chosen. selected-key with selection-change hands the choice to the caller.
disabled-keys takes individual segments out, and is-disabled freezes the whole control — the selection stays visible but cannot be moved, which is the right shape for a read-only view.
The track lands on 28, 32, 36 and 40 pixels for the four sizes, the same heights a button and a field stand at, so a segmented control lines up with either beside it.
Accessibility
- The control has no visible label, so
aria-labelis not optional — "Reporting range" is what turns three unexplained words into a question. - The indicator is a picture of the selection. What is announced is the segment's own
aria-checked, so the control reads correctly while the highlight is still sliding. - To a screen reader this is a radio group —
role="radiogroup"on the track androle="radio"on each segment. What differs is the form story: a RadioGroup submits under anameand carries a validation state, and this does not. Reach for that one where the choice is a field rather than a view switch.
API
SegmentedControl
| Prop | Type | Default | Description |
|---|---|---|---|
ariaDescribedby | string | — | |
ariaLabel | string | — | Names the control, which has no visible label of its own. Declared under this name because Vue normalises prop names, so a hyphenated one never resolves — it is mapped back to aria-label at the binding. |
ariaLabelledby | string | — | |
defaultSelectedKey | CollectionKey | — | The initially selected segment. Falls back to the first segment that is not disabled. |
disabledKeys | CollectionKey[] | — | |
fullWidth | boolean | — | Stretches the track across its container and shares the width between the segments. |
isDisabled | boolean | — | Disables every segment: a selection that stays visible but cannot be moved. |
selectedKey | CollectionKey | — | The selected segment, when the caller drives it. |
size | "xs" | "sm" | "md" | "lg" | "md" | The control's scale. The track lands on 28/32/36/40px, the four heights a button and a field stand at, so a segmented control lines up with either. |
The default slot receives:
| Slot prop | Type |
|---|---|
isDisabled | boolean |
selectedKey | CollectionKey | null |
| Event | Payload |
|---|---|
selectionChange | CollectionKey |
update:selectedKey | CollectionKey |
SegmentedControlIndicator
SegmentedControlIndicator takes nothing but class.
SegmentedControlItem
| Prop | Type | Default | Description |
|---|---|---|---|
ariaLabel | string | — | Names the segment, for one drawn as an icon with no text beside it. |
id* | CollectionKey | — | Identifies the segment, and is what the selection reports. Deliberately does not reach the DOM as an id, so two controls that both hold a "weekly" segment cannot collide. It surfaces as data-key instead. |
isDisabled | boolean | — | |
textValue | string | — | What typeahead and assistive technology read, when the rendered text will not do. |
The default slot receives:
| Slot prop | Type |
|---|---|
isDisabled | boolean |
isFocused | boolean |
isFocusVisible | boolean |
isHovered | boolean |
isPressed | boolean |
isSelected | boolean |
SegmentedControlSeparator
SegmentedControlSeparator takes nothing but class.