Slider
Slider — a value or a range on a track: a bid, a budget, a scale.
Beta · Forms · packages/css/src/components/slider.css
.pui-slider on input[type=range], the fill at --pui-slider-value; .pui-slider-range parts for a scripted two-thumb range. The value is text beside the track, never on the thumb.
Sizes across, states down.
What it is for
Section titled “What it is for”- Type: single (one thumb, the range from the start) or range (two thumbs, the range between them)
- States: default, hover, focus, disabled — no error state: a slider cannot hold an invalid value
- One size, horizontal; constraints scale, so a stretched instance keeps its thumb at its value
- The value is the consumer’s text beside the track (label 44 wide, value in 600 at the right — the examples), never drawn on the thumb
Use when a number within known bounds where the rough position matters more than the exact digit — a bid ceiling, a daily budget, opacity, a scale — and the bounds fit on a track.
Do not use when the exact number is what the user types (Input with a suffix); the range is unbounded or huge (Input); the choice is discrete and few (Toggle group, Radio); on a touch screen at 16px without a larger hit area (the code side adds it).
Relates to Input, Input group, Switch, Toggle group, Field, Label.
Anti-patterns a slider without its value shown · a thumb dragged past its range’s end · two sliders for min and max (that is Type range) · the browser’s own range control in a product screen · a fill changed on the instance.
Keywords: slider, range, bid, budget, scale, track, thumb
Figma — page Slider: Slider (8 variants)
shadcn: slider
The markup — copy this
Section titled “The markup — copy this”The class, the parts, and nothing that is not in the package. The same block opens slider.css.
<input class="pui-slider" type="range" aria-label="Volume" min="0" max="100" value="50" style="--pui-slider-value: 50%">Rule — the value is text beside the track (label 44 wide, the number in 600 at the right), never on the thumb.
Accessibility — measured, not assumed
Section titled “Accessibility — measured, not assumed”Every number here is measured on the rendered component: contrast (npm run contrast:render), the focus ring (npm run focus) and the keyboard (npm run keyboard). The floors are principle 12’s.
Contrast
Section titled “Contrast”| ink on ground | reads | floor | the matrix calls it | |
|---|---|---|---|---|
#544d4d on #ffffff |
8.24 | 4.5 | text.muted on surface.page (promised) | ok |
#0b0202 on #ffffff |
20.51 | 4.5 | text.default on surface.page (promised) | ok |
2 distinct pair(s) rendered, 0 that axe calls a violation.
The focus ring
Section titled “The focus ring”| primitive | on | the indicator | over | the change | |
|---|---|---|---|---|---|
| Slider | surface/page | shadow-inset #6a66e4 2 px |
#ffffff |
4.53 | ok |
| Slider | surface/card | shadow-inset #6a66e4 2 px |
#ffffff |
4.53 | ok |
| Slider | surface/sunken | shadow-inset #6a66e4 2 px |
#ffffff |
4.53 | ok |
| Slider - range thumb | surface/page | shadow #6a66e4 2 px |
#ffffff |
4.53 | ok |
| Slider - range thumb | surface/card | shadow #6a66e4 2 px |
#f2f2f7 |
4.06 | ok |
| Slider - range thumb | surface/sunken | shadow #6a66e4 2 px |
#f2f2f2 |
4.05 | ok |
3 of 3 focus stop(s) in this block meet WCAG 2.4.13 on screen — the same crop screenshotted focused and unfocused, and the difference measured.
Keyboard
Section titled “Keyboard”What the consumer’s script owes. all of it is the browser’s: input[type=range] takes the arrow keys by step, Home / End, and PageUp / PageDown by a larger step. A scripted range slider owes the same on its thumb.
Tab order across the whole library is document order over 344 stops, and Shift+Tab is its exact reverse — no keyboard trap anywhere (WCAG 2.1.2).
Pepper UI v1.5.0
The Mobupps design system. 386 tokens, 88 components, 65 pages in the workshop — every page of this site generated from the repository, so nothing here is typed twice.