Skip to the content

Kongens Nytorv

Metro M1, M2 and M3.

Variants and states

RestDisabled
Default
Default
  • Rest
  • Disabled

SegmentedControl styles hover, pressed and focus on its inner parts, which a still preview can't reach, so this table shows rest and disabled only.

Props

NameTypeDefaultDescription
valuestring—The selected segment's value, when the caller controls it. A value no segment has selects none.
defaultValuestring—The segment selected at first, when the control keeps the value itself. Left out, with no value, no segment is selected until one is chosen.
onChange(event: Event, value: string, details: ToggleGroup.ChangeEventDetails) => void—Called when another segment is selected, by a click, Enter or Space (details.reason 'none'), with that segment's value. Not called when the selected segment is pressed again. event is details.event.
disabledbooleanfalseWhether every segment ignores the pointer and the keys. The selected segment still shows, and the control leaves the tab order.
childrenReactNode—The control's Segments, in reading order.
classNamestring—Reaches the root. className is merged after pn-SegmentedControl.
styleCSSProperties—Reaches the root. className is merged after pn-SegmentedControl.
refRef<HTMLDivElement>—Reaches the root. className is merged after pn-SegmentedControl.
valuestring, default —
The selected segment's value, when the caller controls it. A value no segment has selects none.
defaultValuestring, default —
The segment selected at first, when the control keeps the value itself. Left out, with no value, no segment is selected until one is chosen.
onChange(event: Event, value: string, details: ToggleGroup.ChangeEventDetails) => void, default —
Called when another segment is selected, by a click, Enter or Space (details.reason 'none'), with that segment's value. Not called when the selected segment is pressed again. event is details.event.
disabledboolean, default false
Whether every segment ignores the pointer and the keys. The selected segment still shows, and the control leaves the tab order.
childrenReactNode, default —
The control's Segments, in reading order.
classNamestring, default —
Reaches the root. className is merged after pn-SegmentedControl.
styleCSSProperties, default —
Reaches the root. className is merged after pn-SegmentedControl.
refRef<HTMLDivElement>, default —
Reaches the root. className is merged after pn-SegmentedControl.

Use it

import { SegmentedControl } from '@mylder/perron'

Ask your agent

get_reference({ library: "base-ui", component: "ToggleGroup" })get_reference({ library: "base-ui", component: "Toggle" })

Keyboard and ARIA

From the Base UI reference for ToggleGroup and Toggle and the installed ToggleGroup, Toggle and the composite root and item they build on. "From" says who does it.

KeyDoesFrom
TabMoves focus into the control, to its one tab stop: the first enabled segment, or the segment focused last; the next Tab leaves the controlBase UI
Shift+TabMoves focus out of the control, backwardsBase UI
ArrowRightMoves focus to the next enabled segment, wrapping from the last to the first while loopFocus is on, without selecting it; the previous one under an rtl DirectionProvider, which Perron doesn't set upBase UI
ArrowLeftMoves focus to the previous enabled segment, wrapping from the first to the last while loopFocus is on, without selecting it; the next one under an rtl DirectionProviderBase UI
Home, EndMove focus to the first and the last enabled segmentBase UI
Enter, SpaceSelect the focused segment and call onChange; nothing on the selected segment, whose change Perron cancels (CR-4)The browser's click; Base UI for a non-button render

ArrowUp and ArrowDown do nothing: the control runs horizontally, and the component adds no keys of its own.

ElementRoleAccessible name fromStates announced
rootgroup, from Base UIThe caller's aria-label or aria-labelledbynone
segmentbutton, a native <button>, announced as a toggle by aria-pressedIts text content: the caller's childrenaria-pressed; disabled by the native disabled

What axe won't catch, from the contract, each with how this component meets it:

  • Everything the eye is told, the ear is told, for every shape each prop accepts: the selected segment, which the raised fill and the shadow show, is aria-pressed="true" and every other segment "false"; a disabled segment's tertiary colour is the native disabled, announced as dimmed; a disabled control shows it on each of its segments, which Base UI disables.
  • Every landmark and named region has an accessible name: the control is a group, not a landmark, named by the caller's aria-label or aria-labelledby, which every story sets, so a screen reader says what the choice is about before its segments.
  • Every default label can be overridden: none here; the control owns no strings.
  • Every shape the type accepts renders, in every variant: a segment's children render a string, an element and a list alike, as one label whose text and elements flow and wrap as one run of text, as the LabelShapes story shows.
  • A hidden copy kept for animation is aria-hidden, and a collapsed region is inert: none here; the control keeps no copy and collapses nothing.
  • Native semantics first: native <button>s from Toggle, with aria-pressed, in Base UI's group, with ARIA from the caller only for the group's name.
  • Focus moves in reading order and returns on close: the arrow keys move through the segments in document order, and Tab leaves the control after its one stop; the control opens and closes nothing, and focus stays on the segment it selects.
  • Every target is at least size.target-min square: the smallest target is a segment with a one-letter label, size.segment (32 px) tall and its label plus space.300 on each side (at least 24 px) wide.
  • Loops stop when the system asks for less motion: none here; the control has no loop and no transition.

Owned strings

No owned strings: every word comes from the caller, as a segment's children or the control's aria-label.

Do and don't

For a caller using the component, with the reason. Each row is a rule: a must row's Don't is never right, a should row's needs a reason, and Checked by says what catches the Don't in a caller's code.

RuleLevelDoDon'tChecked by
DD-1shouldUse a SegmentedControl to pick how one view shows its content, such as departures by mode or a chart by day or weekUse it to switch between views of one thing: Tabs change which view shows, a segmented control changes how one view showsreview
DD-2shouldUse it for one choice of two to fiveUse it for filters that turn on and off apart, or for more than five choices: filter chips take several, and a long row of segments outgrows a phonereview
DD-3mustName the control with aria-label or aria-labelledby, such as "Mode", so a screen reader says what the choice is aboutLeave the control unnamed: its segments' words alone don't say what they choose betweenreview
DD-4shouldGive it a defaultValue or a value, so one segment is always selectedLeave nothing selected without a reason: a control with no raised segment reads as brokenreview
DD-5mustKeep each label to a word or two, in sentence case: "Bus", "Planned works"Write a sentence in a segment, or rely on a label's colour or an icon alone to say what it choosesreview
DD-6shouldShow a segment whose view is empty, and say so in the view with an EmptyState or a DataStatePanelDisable a segment because its view has no data: a disabled segment can't say why, and leaves the key orderreview
DD-7mustRun an action with a Button, and group actions in a ToolbarUse a segment as an action or as navigation: pressing one selects it and keeps it selected, and a link to another screen is a LinkButtonreview