Skip to content

ComponentsForms

Slider

Lets users pick a number, or a range between two numbers, by dragging a thumb along a track. Locale-aware value formatting, steps, tick marks, seven color tones and two sizes, with full keyboard support.

React AriaSource
60

Installation

pnpm dlx shadcn@latest add @desyne/slider

The CLI installs dependencies and any other components this one uses.

Usage

tsx
import { Slider } from "@/components/ui/slider";
tsx
<Slider label="Volume" defaultValue={60} />

<Slider label="Price" defaultValue={[200, 800]} maxValue={1000} />

Pass a number for a single thumb, or an array for one thumb per value. The type of value, defaultValue and onChange follows whichever you pass.

When to use

  • Slider — an approximate value within a known range where relative position matters more than precision: volume, opacity, a price range.
  • Number Field — an exact number, or a range too large to drag through. Pair the two when users need both (example).
  • Radio Group or Select — a handful of discrete, named options rather than a continuous scale.
  • Progress Bar or Meter — displaying a value users can't change.

Anatomy

tsx
<Slider>        {/* root: label, output, track, marks */}
  Label         {/* from `label` */}
  Output        {/* formatted value, from `showOutput` */}
  Track         {/* background, filled range and one thumb per value */}
  Marks         {/* from `marks` */}
</Slider>
PartRendersNotes
Slider<div role="group">Root. Sets the tone variables from color.
Label<label>Rendered from label.
Output<output>Current value(s), formatted with formatOptions. Two values are formatted as a locale-aware range. Hidden with showOutput={false}.
Track<div>Muted background plus a filled segment from the start (or between two thumbs).
Thumb<div> + hidden <input type="range">One per value. Grows a soft ring on hover, focus and drag.
Marks<div aria-hidden>Numeric labels positioned along the track from marks. Hidden from screen readers, which announce the thumb's value instead.

Examples

Range

Pass an array to defaultValue (or value) for two thumbs. The fill spans between them, and thumbs can't cross each other. Each thumb gets its own accessible label: two-thumb sliders default to "Minimum" and "Maximum", and thumbLabels sets your own (e.g. ["Start", "End"]).

$200 – $800

Step, min and max

minValue and maxValue default to 0 and 100, and step to 1. Values snap to the step while dragging and with the keyboard.

21.5°C

Value formatting

formatOptions takes any Intl.NumberFormat options. The output and the value screen readers announce are both formatted in the user's locale: percentages, currencies and units.

80%
€2,500
250 MB

Fill offset

By default the fill starts at minValue. For a single thumb, fillOffset starts it from another value instead, such as 0 on a -12 to 12 scale, so the fill grows in either direction. The equalizer in the next example uses fillOffset={0}.

Vertical

orientation="vertical" stacks the label and output above a vertical track. Marks sit beside the track. A vertical slider is h-48 by default; set a height with className (e.g. h-56). Sizes, colors, ranges and marks all work the same way. Up and down arrows move the thumb.

+4
+2
-1
+3
+5
20–80

Marks

marks renders labels under the track at the given values. Match them to step so every mark is reachable. Marks show raw numbers; they don't use formatOptions.

30

Colors

color accepts any tone and defaults to brand. Use neutral for media controls and danger or warning only when the value itself signals risk.

Sizes

md is the default. sm has a thinner track and a smaller thumb for dense panels.

40
60

With icons, no visible label

Set showOutput={false} and put icons on either side for a compact control. Without a label, an aria-label is required.

Disabled

isDisabled dims the slider and removes every thumb from the tab order.

3

Controlled

onChange fires continuously while dragging; onChangeEnd fires once when the user lets go (or after each key press). Update the UI with the first and save or fetch with the second.

40

Aa Bb Cc

onChange: 40px · onChangeEnd: 40px

With a number field

Share one state between a slider and a NumberField so users can drag for speed or type for precision.

Form submission

Pass name and each thumb's hidden range input is submitted with the form. For a range, a string names every thumb, so read it with formData.getAll(name); an array such as ["ageMin", "ageMax"] names each thumb separately. form associates the inputs with a <form> elsewhere in the document by id. A disabled slider is not submitted.

80
18–65
9–17

Recipes

Price filter

A range slider kept in sync with two number fields, with a live result count.

$100 – $900
–

Image adjustments

Small neutral sliders driving CSS filters on a preview, with a reset.

100
100
100
0

Pricing calculator

Two sliders feeding a live monthly estimate, one with marks and one formatted in gigabytes.

Estimate your bill

$12 per seat, $0.25 per GB of storage.

25
500 GB

Estimated monthly

$425

Accessibility

  • Each thumb contains a visually hidden <input type="range">, so screen readers announce it as a slider with its label, current value, minimum and maximum.
  • The announced value uses formatOptions (e.g. "80%", "€2,500"), and the visible output is an <output> element linked to the thumbs.
  • Without a label, pass aria-label or aria-labelledby.
  • In a range, each thumb input has its thumb label as aria-label, combined with the slider label through aria-labelledby, so screen readers can tell the thumbs apart. Override the defaults with thumbLabels.
  • Clicking anywhere on the track moves the nearest thumb there; thumbs can also be dragged with mouse, touch or pen.
  • In right-to-left locales the track direction and arrow keys are mirrored.
  • The focus ring only appears for keyboard focus (data-focus-visible).

Keyboard

KeyAction
TabMoves focus to the next thumb
→ / ↑Increases the value by one step
← / ↓Decreases the value by one step
Page Up / Page DownIncreases / decreases by a larger step
Home / EndSets the minimum / maximum value

Styling

Data attributes

On the Slider root:

AttributePresent when
data-disabledisDisabled is true
data-orientation"horizontal" or "vertical"

On each thumb (style them from the root with arbitrary variants such as [&_[data-dragging]]:…):

AttributePresent when
data-draggingBeing dragged
data-hoveredHovered with a mouse or pen
data-focused / data-focus-visibleFocused / focused with the keyboard
data-disabledThe slider is disabled

Slots

data-slotElement
sliderRoot
labelThe label
slider-trackThe track (click and drag target)
slider-fillThe filled segment
slider-thumbEach thumb

Tone variables

color sets --tone on the root. The filled track, the thumb border and its ring all use it, so a one-off color is a single class:

tsx
<Slider label="Heat" className="[--tone:var(--color-orange-500)]" defaultValue={70} />

Render props

className accepts a function of the slider state (orientation, isDisabled, state):

tsx
<Slider className={({ isDisabled }) => (isDisabled ? "grayscale" : "")} />

API Reference

Slider

Prop

Type

Also accepts every prop of React Aria's Slider.