Slider
StableSelects a value, or a range of values, by dragging along a track — best when the approximate position matters more than the exact number.
Anatomy
- 1TrackThe full range of values, in a neutral tint.
- 2RangeThe selected part of the range, filled with the brand color — from the start, or between two thumbs.
- 3ThumbThe handle. It's the focusable part, with a 32px hit area; add a second thumb to select a range.
Installation
$ pnpm dlx shadcn@latest add https://www.prfct.dev/r/slider.jsonUsage
import { Slider } from "@/components/ui/slider"<Slider defaultValue={50} aria-label="Volume" />Pass a number for a single thumb and an array for a range — one thumb per value. The filled part of the track and the thumb's border use the brand color.
Examples
With a label and value
Show the current value next to the label whenever the number matters. Label the slider with aria-labelledby pointing at a visible label; the name is forwarded to the thumb, the element screen readers actually focus.
Range
An array value renders two thumbs. minStepsBetweenValues keeps them from overlapping, and getAriaLabel gives each thumb its own name — Minimum price and Maximum price — so they aren't announced as two identical sliders.
Steps
step snaps the value to increments. For a handful of discrete values, draw tick labels under the track and describe the value in words with getAriaValueText — 3 replicas is clearer than 3.
Vertical
orientation="vertical" suits controls that map to height — levels, equalizers, zoom. Give the slider a height through its container.
Disabled
A disabled slider keeps showing its value at half opacity and ignores input. Say why nearby when it isn't obvious.
Guidelines
When to use
- When relative position matters more than precision: volume, opacity, zoom, a price range.
- When people benefit from seeing the value in the context of its full range.
When not to use
- When an exact number matters — use an Input with
type="number", or pair the slider with one. - For very large ranges where one pixel covers many values — use an input.
- For a few named options — use a Radio Group or Toggle Group.
Show the value
A slider without a visible value asks people to guess. Show the value next to the label, format it ($240, 80%) with the format prop or your own formatter, and update it live while dragging.
Commit, don't flood
onValueChange fires continuously while dragging — use it to update the display. Use onValueCommitted to save or fetch once the drag ends, so a single adjustment doesn't send fifty requests.
Accessibility
Each thumb contains a native <input type="range">, so the slider works with screen readers, voice control and browser form features out of the box.
| Key | Behavior |
|---|---|
Tab | Moves focus to the next thumb. Each thumb of a range is its own tab stop. |
→↑ | Increases the value by one step. |
←↓ | Decreases the value by one step. |
PageUpShift↑ | Increases the value by the large step (10 by default). |
PageDownShift↓ | Decreases the value by the large step. |
HomeEnd | Sets the minimum or maximum value. |
- Name it. Use
aria-labelledbypointing at a visible label, oraria-label. prfct forwards the name to the thumbs; for ranges, name each thumb withgetAriaLabel. - Describe the value.
formatshapes both the visible and the announced value;getAriaValueTextoverrides what's announced when words say it better than numbers. - Boundaries. The thumb has a 2px brand border, keeping it at least 3:1 against any surface (WCAG 1.4.11). The track isn't needed to identify the control, so it stays quiet.
- Target size. Thumbs are 16px with a transparent hit area of 32×32px, and grow slightly while hovered or dragged.
API reference
Slider
Renders a <div role="group"> with a track and one thumb per value. Accepts every prop of Base UI's Slider.Root.