Skip to content

Range

A slider for one value, or for an interval with variant="range", rendered as <input is="root-range" type="range">.

Usage

A single-thumb range:

<input is="root-range" type="range" data-label="Volume" min="0" max="100" step="1" value="40"
       data-value-format="({value}%)" />

A dual-thumb interval range (variant="range"):

<input is="root-range" type="range" variant="range" data-label="Price" min="0" max="100" low="20" high="80"
       data-value-format="({low}€ - {high}€)" data-value-decimals="2" />

The field around it

A range has no field box - no frame, no ground, nothing to put padding inside - so what it takes from Input, Select and Textarea is the composition rather than the skin: the same data-label, the same required marker, the same hint node under it, at the same steps. fieldDecorator builds all of it, which is why the label is data-label and not a label attribute of its own. It was one, for a while: the one field in the library whose name the decorator never saw, so a range that asked for a label got a group name for assistive tech and nothing on screen.

<input is="root-range" type="range" data-label="Budget" data-hint="Monthly, before tax" min="0" max="500" value="180" required />
<input is="root-range" type="range" data-label="Budget" data-error="Above the plan limit" data-invalid="true" min="0" max="500" value="480" />

The value in the label

A slider's value is the one thing about it that is invisible: the thumb says roughly where in the interval it sits, and nothing says what that is in the units the reader cares about. data-value-format is a template appended to the label - { value} on a single thumb, { low} and { high} on an interval - and data-value-decimals how many places each number takes, so a price reads 20.00 where a percentage reads 20.

It renders inside the label, so a screen reader gets the value with the name rather than having to reach the slider to find it.

<input is="root-range" type="range" data-label="Brightness" min="0" max="100" step="5" value="65"
       data-value-format="({value}%)" />
<input is="root-range" type="range" variant="range" data-label="Budget" min="0" max="500" low="120" high="380"
       data-value-format="({low}€ - {high}€)" data-value-decimals="2" data-hint="Monthly, before tax" />

The interval

variant="range" overlays a second range input on a shared track, wraps the pair in a [data-part="range"] group and paints the fill between the two thumbs. low and high are where they start, and moving either attribute afterwards moves the thumb: each clamps against the other, so neither can be dragged - or set - past its partner.

The track fills the row it is in, which is what the [field-wrapper] is for. Left unstyled that wrapper was an inline, shrink-to-fit <span>, and the group asking it for inline-size: 100% got a percentage of a width still being computed: both thumbs are absolutely positioned, so the group's min-content contribution is zero and the whole interval range collapsed to two thumbs stacked on each other.

<input is="root-range" type="range" variant="range" data-label="Delivery window" min="8" max="20" step="1" low="10" high="14" data-hint="Hours, 24-hour clock" />

Sizes

data-size takes small and large; medium is the default and needs no value written. The step moves the track and the thumb together.

<input is="root-range" type="range" data-size="small" data-label="Small" min="0" max="100" value="30" />
<input is="root-range" type="range" data-label="Medium" min="0" max="100" value="50" />
<input is="root-range" type="range" data-size="large" data-label="Large" min="0" max="100" value="70" />

Attributes

Attribute Type Default Description
value number - Current value (single)
min number 0 Minimum value
max number 100 Maximum value
step number 1 Step increment
variant 'range' - Dual-thumb interval range
low number min Lower bound (range); clamped at high
high number max Upper bound (range); clamped at low
data-size 'small' | 'large' medium Track and thumb scale
data-label string - Label text; also names the group and both thumbs (range)
data-value-format string - Template appended to the label: { value}, or { low} / { high} on a range
data-value-decimals number 0 Decimal places each number in the template takes
required boolean false Marks the field required and draws the asterisk
data-hint string - Description shown under the track
data-error string - Error message; falls back to validationMessage
data-invalid 'true' - Shows the error instead of the description
disabled boolean false Disables the range

Properties

Property Type Description
isRange boolean Whether this is the dual-thumb variant
low / high number The two bounds (range); high is NaN on a single thumb

Events

Event Detail Description
root-range.input { value } / { low, high } Fired on value change
root-range.change { value } / { low, high } Fired when the value is committed

Extends

HTMLInputElement - use with <input is="root-range">. In range mode the two native range inputs are overlaid on a shared track; each keeps role="slider" and gets its own accessible name (… (minimum) / … (maximum)), taken from data-label, with the group taking the label itself.