Skip to the content

Kongens Nytorv

Metro M1, M2 and M3.

Minutes of movement drawn behind each vehicle

5

Variants and states

RestDisabled
Default

Minutes of movement drawn behind each vehicle

5

Minutes of movement drawn behind each vehicle

5
Default
  • Rest

    Minutes of movement drawn behind each vehicle

    5
  • Disabled

    Minutes of movement drawn behind each vehicle

    5

Slider 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
label*ReactNode—Required. What the number is, in sentence case, such as "Trail length": shown above the slider, and the name of the slider's group and of a single thumb; a range's thumbs are named "Minimum" and "Maximum".
hiddenLabelbooleanfalseWhether the label is heard but not seen. Use it only where the screen around the slider already says what it is for.
descriptionReactNode—A line of help between the label and the slider, such as "Minutes of movement drawn behind each vehicle", read after the label by a screen reader. Left out, no description is rendered.
errorReactNode—What is wrong with the value and how to put it right, such as "Choose 8 minutes or fewer". Given, it marks the slider invalid and is shown under it; left out, the slider shows Base UI's own message when its checks fail.
disabledbooleanfalseWhether the slider ignores the person: no thumb takes focus, a press or a key changes nothing, and the label, the help, the fill and the figure turn to the tertiary ink.
valuenumber | readonly [ number, number ]—The value, when the caller controls it: a number for one thumb, or a pair for a range, its two thumbs at the lower and the upper end.
defaultValuenumber | readonly [ number, number ]—The value at first, when the slider keeps it itself: a number, or a pair for a range. Left out, a single thumb starts at min.
onChange(event: Event, value: number | readonly [number, number], details: Slider.Root.ChangeEventDetails) => void—Called at every step the value moves, with the new value: by a key (details.reason 'keyboard'), a drag ('drag'), a press on the track ('track-press'), or a screen reader or the browser setting the hidden range input itself ('input-change'); details.cancel() keeps the value as it was. event is details.event, whose target holds value and name, for a form library.
onChangeCommitted(event: Event, value: number | readonly [number, number], details: Slider.Root.CommitEventDetails) => void—Called once the person settles on a value: when a drag ends (details.reason 'drag'), the track is pressed ('track-press'), a key is pressed ('keyboard'), or a screen reader or the browser sets the hidden range input itself ('input-change'). It is not called when the value didn't change. Use it to act once on the final value, such as to fetch, rather than at every step. event is details.event.
localeLocalesArgumentThe PerronProvider's localeThe locale Intl.NumberFormat formats the figure and each thumb's value text in: "1.5 km" in English, "1,5 km" in Danish, Swedish and Norwegian. Left out, the nearest PerronProvider's.
minimumLabelstringThe locale'sOverrides "Minimum", the name of a range's lower thumb.
maximumLabelstringThe locale'sOverrides "Maximum", the name of a range's upper thumb.
refRef<HTMLDivElement>—Reaches the root, the Slider.Root <div>.
slotProps{ field?: Omit<FieldRootProps, "children" | "disabled" | "name"> | undefined; label?: FieldLabelProps | undefined; description?: FieldDescriptionProps | undefined; error?: FieldErrorProps | undefined; control?: SliderControlProps | undefined; track?: SliderTrackProps | undefined; indicator?: SliderIndicatorProps | undefined; thumb?: Omit<SliderThumbProps, "index"> | undefined; value?: Omit<SliderValueProps, "children"> | undefined; }—Props for each part: field, label, description, error, control, track, indicator, thumb, value.
label (required)ReactNode, default —
Required. What the number is, in sentence case, such as "Trail length": shown above the slider, and the name of the slider's group and of a single thumb; a range's thumbs are named "Minimum" and "Maximum".
hiddenLabelboolean, default false
Whether the label is heard but not seen. Use it only where the screen around the slider already says what it is for.
descriptionReactNode, default —
A line of help between the label and the slider, such as "Minutes of movement drawn behind each vehicle", read after the label by a screen reader. Left out, no description is rendered.
errorReactNode, default —
What is wrong with the value and how to put it right, such as "Choose 8 minutes or fewer". Given, it marks the slider invalid and is shown under it; left out, the slider shows Base UI's own message when its checks fail.
disabledboolean, default false
Whether the slider ignores the person: no thumb takes focus, a press or a key changes nothing, and the label, the help, the fill and the figure turn to the tertiary ink.
valuenumber | readonly [ number, number ], default —
The value, when the caller controls it: a number for one thumb, or a pair for a range, its two thumbs at the lower and the upper end.
defaultValuenumber | readonly [ number, number ], default —
The value at first, when the slider keeps it itself: a number, or a pair for a range. Left out, a single thumb starts at min.
onChange(event: Event, value: number | readonly [number, number], details: Slider.Root.ChangeEventDetails) => void, default —
Called at every step the value moves, with the new value: by a key (details.reason 'keyboard'), a drag ('drag'), a press on the track ('track-press'), or a screen reader or the browser setting the hidden range input itself ('input-change'); details.cancel() keeps the value as it was. event is details.event, whose target holds value and name, for a form library.
onChangeCommitted(event: Event, value: number | readonly [number, number], details: Slider.Root.CommitEventDetails) => void, default —
Called once the person settles on a value: when a drag ends (details.reason 'drag'), the track is pressed ('track-press'), a key is pressed ('keyboard'), or a screen reader or the browser sets the hidden range input itself ('input-change'). It is not called when the value didn't change. Use it to act once on the final value, such as to fetch, rather than at every step. event is details.event.
localeLocalesArgument, default The PerronProvider's locale
The locale Intl.NumberFormat formats the figure and each thumb's value text in: "1.5 km" in English, "1,5 km" in Danish, Swedish and Norwegian. Left out, the nearest PerronProvider's.
minimumLabelstring, default The locale's
Overrides "Minimum", the name of a range's lower thumb.
maximumLabelstring, default The locale's
Overrides "Maximum", the name of a range's upper thumb.
refRef<HTMLDivElement>, default —
Reaches the root, the Slider.Root <div>.
slotProps{ field?: Omit<FieldRootProps, "children" | "disabled" | "name"> | undefined; label?: FieldLabelProps | undefined; description?: FieldDescriptionProps | undefined; error?: FieldErrorProps | undefined; control?: SliderControlProps | undefined; track?: SliderTrackProps | undefined; indicator?: SliderIndicatorProps | undefined; thumb?: Omit<SliderThumbProps, "index"> | undefined; value?: Omit<SliderValueProps, "children"> | undefined; }, default —
Props for each part: field, label, description, error, control, track, indicator, thumb, value.

Use it

import { Slider } from '@mylder/perron'

Ask your agent

get_reference({ library: "base-ui", component: "Slider" })get_reference({ library: "base-ui", component: "Field" })

Keyboard and ARIA

From the Base UI reference for Slider and the installed SliderRoot, SliderControl, SliderThumb and SliderValue, and Field's spec for the frame. Slider adds no keys or pointer handling of its own.

Key or pressDoesFrom
Tab, Shift+TabMove focus to and from each thumb's input in turn: one tab stop per thumb, the lower thumb first in a range; the label, the figure and the track take noneBase UI
ArrowRight, ArrowUpRaise the focused thumb's value by step; ArrowRight lowers it only inside Base UI's DirectionProvider set to rtl, which PerronProvider doesn't renderBase UI
ArrowLeft, ArrowDownLower the focused thumb's value by step; ArrowLeft raises it only inside Base UI's DirectionProvider set to rtl, which PerronProvider doesn't renderBase UI
Shift with an arrow keyMove the value by largeStep in the arrow's directionBase UI
PageUp, PageDownRaise or lower the value by largeStepBase UI
Home, EndMove the value to min or max; in a range, the upper thumb's Home and the lower thumb's End stop minStepsBetweenValues steps short of the other thumbBase UI
A press or drag on the controlMoves the nearest thumb to the pointer, focuses it without the ring, and follows the drag until releaseBase UI
A press on the labelFocuses a single thumb's input, natively through htmlFor; in a range the label's htmlFor names no input, and a press focuses nothingBase UI
ElementRoleAccessible name fromStates announced
rootgrouparia-labelledby the field's label: "Trail length"aria-describedby the description and the mounted error; aria-invalid while invalid and not disabled
A thumb's inputslider, a native <input type="range">A single thumb: aria-labelledby the field's label, and the native label through htmlFor, "Trail length". A range: aria-label the owned "Minimum" and "Maximum"aria-valuenow, the native min and max, aria-valuetext (the formatted value when format is given, and always in a range), aria-orientation="horizontal", aria-describedby, aria-invalid, disabled
valuestatus, a native <output> with aria-live="off"noneNone live: its text, "5", is read in place, and never announced as it changes
valueSizernone: aria-hiddennonenone
label, description, errorField'sField'sField's

The figure stays an <output> with Base UI's aria-live="off": the value is heard from the focused thumb's aria-valuenow or aria-valuetext at every step, so a live figure would say each step a second time, and Base UI keeps it off for that reason. Read in place, it repeats the value the thumb's input says, which a screen reader's reading of the page expects of a control's visible figure.

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 thumb's place and the figure are the input's aria-valuenow, or its aria-valuetext in the caller's format; a range's two thumbs are named "Minimum" and "Maximum" and each says its own value, never Base UI's English "start range" (CR-7); the description and the error are each thumb's aria-describedby; an invalid slider is aria-invalid and its error is words, never only the thumb's red edge; the sizers, which the eye never sees, are aria-hidden.
  • Every landmark and named region has an accessible name: the root's group is named by the field's label, even hidden; Slider is not a landmark.
  • Every default label can be overridden: minimumLabel and maximumLabel override "Minimum" and "Maximum", and slotProps.thumb.getAriaLabel names the thumbs in the caller's own words (see Owned strings).
  • Every shape the type accepts renders, in every variant: label, description and error render a string, an element and a list alike, by Field; value and defaultValue render one thumb for a number and two for a pair; a long Danish compound in the label or the description wraps, by Field's CR-8, and the figure keeps one line.
  • A hidden copy kept for animation is aria-hidden, and a collapsed region is inert: the two sizers, copies of the end figures kept for the figure's width, are aria-hidden and visibility: hidden; nothing collapses.
  • Native semantics first: Base UI's native <input type="range"> per thumb, its <output> for the figure, a group round them and Field's native <label>; Perron adds no ARIA beyond three attributes: a range thumb's aria-label through Base UI's getAriaLabel and its aria-valuetext through getAriaValueText (CR-7), and aria-hidden on the two sizers (CR-8).
  • Focus moves in reading order and returns on close: each thumb is one tab stop, the lower thumb first, between the label above and the error below; nothing opens or closes.
  • Every target is at least size.target-min square: the control is size.target-min tall across the first column, and a press anywhere on it moves the nearest thumb; the thumb, 18 px, sits inside it.
  • Loops stop when the system asks for less motion: none here; nothing loops and nothing transitions.

Owned strings

In a range, the two thumbs are named by new owned strings, minimum "Minimum" and maximum "Maximum", given to Base UI's Slider.Thumb through getAriaLabel and overridden by minimumLabel and maximumLabel; and each range thumb's aria-valuetext is its formatted value alone, through getAriaValueText, in place of Base UI's default, which appends the English words "start range" and "end range". Base UI's guidance names each thumb of a range with its own aria-label beside the group's visible label, and the ear hears "Departures per hour, group" then "Minimum, slider, 4"; "Minimum" and "Maximum" fit any quantity, where "From" and "To" fit a time but not a count; Base UI's "start range" is English in every locale, which the owned-strings check would fail in Danish; and a single thumb needs no owned word, since the field's label names it.

KeyEnglishOverrideSeen or heard where
minimum"Minimum"minimumLabelHeard as the name of a range's lower thumb, as "Minimum, slider, 4"; never shown
maximum"Maximum"maximumLabelHeard as the name of a range's upper thumb, as "Maximum, slider, 12"; never shown

Both keys are new, described in en.ts as A range slider: the name of its lower thumb, heard as "Minimum, slider, 4". and A range slider: the name of its upper thumb, heard as "Maximum, slider, 12"., with the Danish, Swedish and Norwegian written by the build.

Every other word is the caller's, through label, description and error, or comes from Intl.NumberFormat in the slider's locale and the caller's format, such as the unit in "1.5 km", or is Base UI's message for a failing check, as Field's spec says.

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 slider for a number where the place in a range matters more than the exact figure, such as a trail's length or a walking distanceUse a slider for an exact number the person knows, such as a stop number or a year: a number field takes it in one step, where a slider takes many key pressesreview
DD-2shouldGive a label that names the quantity, "Trail length", and put its unit in format, so the figure says "1.5 km"Write the unit into the label alone ("Walking distance in km"): the figure and the ear then say a bare numberreview
DD-3shouldKeep the range short enough that each step is a place the thumb can be put by hand: a few dozen steps across the fieldSet a step so fine that a drag skips values the person wants; give a largeStep for long ranges, so Page Up and Shift with an arrow cross themreview
DD-4shouldAct on onChangeCommitted when a change starts work, such as a fetch or a redraw of the mapFetch on every onChange: a drag calls it at every stepreview
DD-5mustGive a range as a pair, [4, 12], and let Slider name its thumbs "Minimum" and "Maximum", or give minimumLabel and maximumLabelName a range's thumbs with aria-label on slotProps.thumb, which gives both thumbs the same name; use getAriaLabel there, which takes each thumb's indexreview
DD-6mustWord an error as what to do, "Choose 8 minutes or fewer"Blame the person or say only that it failed ("Invalid value"), against Content designreview
DD-7mustPut a slider in a bottom Sheet as it is: it keeps a drag along it from swiping the sheet, and a touch drag across it still swipes (CR-11)Wrap it in another element with data-base-ui-swipe-ignore: with no axis, the wrapper drops the sheet's swipe for every touch on the slider, so a drag across it no longer swipes the sheet; nor remove the control's own, which lets a drag along the slider move the sheetreview
DD-8mustUse a Meter to show a value the person can't changeUse a disabled slider as a meter: it reads as a control that is switched offreview