Slider

Sets a number or a range by dragging along a track.

Examples

Parallel conversations

Parallel conversations

8

Spend alert range

Alert when daily spend leaves

$20 – $80

Value

  • Review sampling

    25%

    one valuedefault

  • Alert when daily spend leaves

    $20 – $80

    range

States

  • rest

  • hover

  • dragging

  • focus-visible

  • disabled

Usage

When to use it
Use
The value sits on a known scale and the person thinks in more or less: sampling rate, concurrency, a spend band.
Use
The person wants to see the value against the whole range while setting it.
Not for
The exact number matters, like a refund amount or a timeout in seconds. Use Input.
Not for
There are fewer than five meaningful positions. Use Segmented control.

Rules

8 rules
Must
Save in onValueCommitted, not onValueChange. Because onValueChange fires on every pixel of a drag, so a save there sends dozens of requests and can land out of order.
Should
Pass showValue and a format when the value means something on its own.
Must
Put the unit in format, not in the label. Because format also writes aria-valuetext, so without it a screen reader reads "0.25" where the eye sees "25%".
Must
Pass thumbLabels on a two-thumb range. Because both thumbs otherwise share the one name, and a screen reader cannot tell the lower bound from the upper.
Must
Name a single slider with aria-label or aria-labelledby. Because the thumb is a hidden input with no label of its own, so a screen reader reads only "slider".
Must
Give the track at least 160px. Because below that one step on 0 to 100 is under 2px and the thumb cannot land on a chosen value.
Never
Fill the track with a hue or gradient; the range is ink on the row rule. Because a hue on the range reads as a status, good or bad, that the value does not have.
Never
Render a slider whose min equals max. Because the thumb cannot move, so the person drags a control that changes nothing.

Accessibility

5 checks
Each thumb is a slider input with aria-valuenow, aria-valuemin, aria-valuemax and aria-valuetext from format.
Arrow keys move by step, mirrored in RTL; Page Up and Page Down move by largeStep; Home and End jump.
Tab moves to the second thumb of a range.
The read-out is an output that announces politely; its width stand-ins are aria-hidden.
The control is touch-none so a horizontal drag moves the thumb and a vertical swipe scrolls.

Edge cases

9 edge cases
Long read-out in 320px
The read-out takes its widest width and the track shrinks.
Container 120px
The track shrinks beside the read-out and never overflows.
Right to left
The range fills from the right and the arrows follow.
Zoom 200%
The read-out doubles and the track shrinks; the thumb stays 16px.
Held arrow key
One step per repeat, stopping at max; the read-out reserves the widest of min, max and one step in from each.
On the inverse surface
Ink and paper flip.
Failed save
Set value back; the thumb jumps to it.
Forced colors
Track has a CanvasText border, range is Highlight, thumb is CanvasText.
Reduced motion
The thumb never grows; hover and drag only step its ink.

API

8 props
value / defaultValue
number | number[] default min
onValueChange / onValueCommitted
(value, details) => void
min, max, step, largeStep
number default 0, 100, 1, 10
format
Intl.NumberFormatOptions
locale
Intl.LocalesArgument default 'en-US'
showValue
boolean default false
thumbLabels
string[]
orientation, disabled, name
Base UI default 'horizontal'

Tokens

13 tokens
--line-row
oklch(var(--ink-c) / 0.08)
--line-control
oklch(var(--ink-c) / 0.16)
--radius-soft
6px
--ink
oklch(var(--ink-c))
--paper
oklch(var(--paper-c))
--text-disabled
oklch(var(--ink-c) / 0.40)
--surface-disabled
color-mix(in oklch, var(--paper), var(--ink) 8%)
--line-focus
2px
--border-focus
var(--ink)
--focus-offset
2px
--type-label
400 14px/16px var(--font-sans)
--ring-thumb
0 0 0 2px var(--paper)
--button-primary-hover
oklch(var(--ink-c) / 0.86)

Install

For your coding agent

GitHub

Please star me pookie

141

A new design system every week

Leave your email before you copy the prompt.