Skip to content

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.

ts
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.

size
template
<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-label is 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 and role="radio" on each segment. What differs is the form story: a RadioGroup submits under a name and 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

PropTypeDefaultDescription
ariaDescribedbystring—
ariaLabelstring—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.
ariaLabelledbystring—
defaultSelectedKeyCollectionKey—The initially selected segment. Falls back to the first segment that is not disabled.
disabledKeysCollectionKey[]—
fullWidthboolean—Stretches the track across its container and shares the width between the segments.
isDisabledboolean—Disables every segment: a selection that stays visible but cannot be moved.
selectedKeyCollectionKey—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 propType
isDisabledboolean
selectedKeyCollectionKey | null
EventPayload
selectionChangeCollectionKey
update:selectedKeyCollectionKey

SegmentedControlIndicator

SegmentedControlIndicator takes nothing but class.

SegmentedControlItem

PropTypeDefaultDescription
ariaLabelstring—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.
isDisabledboolean—
textValuestring—What typeahead and assistive technology read, when the rendered text will not do.

The default slot receives:

Slot propType
isDisabledboolean
isFocusedboolean
isFocusVisibleboolean
isHoveredboolean
isPressedboolean
isSelectedboolean

SegmentedControlSeparator

SegmentedControlSeparator takes nothing but class.