Slider
Sets a value, or a range of values, by moving a handle along a track, with an input beside it for an exact number. Use it where the position in the range matters as much as the number.
Live preview
Rendered by the component itself from the same generated tokens as the rest of the site.
const [value, setValue] = useState(40)
<Slider
label="Opacity"
value={value}
onChange={setValue}
/>Installation
Install it with the shadcn CLI, along with everything it uses. New project? Set it up first, as Quick start shows.
npx shadcn@latest add https://www.graphite-ui.com/r/slider.jsonimport { Slider } from '@/components/ui/slider'Anatomy
The label, then the minimum, the track and the maximum, and a Text input for the exact value, 16 from the track. The track is a 2px rail with the part below the value filled, a small tick at the middle and a round handle.
- LabelRequiredInput Label in on-surface-variant, 8 above. Names the group, and each handle and value input through it.
- BoundsRequiredThe min and max values either side of the track, Body/3 on-surface, 8 clear.
- TrackRequiredA 2px rail with the selected part filled, a 2×4 middle tick 1 above it, and a handle per value. Each handle is a native range input; the drawing is laid over it.
- Value inputsOptionalThe governed Text input at Medium, 96 wide, its label hidden, 16 from the track. One for a single slider, after the track; Min before and Max after for a range.
- Supporting textOptionalHelp, error or warning text under the whole row, 8 below.
Variants
Slider - Range has a handle each side, pointing in, and an input for each value. Without inputs, a range shows each value in a bubble over its handle while it is hovered, focused or pressed.
States
Hover grows the handle from 14 to 20. Focus turns the handle and the fill primary; pressing adds a ring. Error and warning reach the value inputs and put their message under the row. Read-only drops the handle and the tick.
API reference
Generated from the contract, versioned with it, and checked by drift-check. This table cannot describe props the component does not have.
| Prop | Type | Default | Notes |
|---|---|---|---|
| value / onChange | — | — | Controlled. A number for the kit's Slider, a two-item tuple for its Slider - Range; the tuple stays ordered, each handle stopping at the other. |
| min / max / step | — | — | 0, 100 and 1 by default. Typing into a value input commits once the text is a value in range; leaving it snaps to the nearest allowed value. |
| showInputs | boolean | — | The kit's Inputs. On by default, as both sets draw them. Without inputs, a range shows each value in a bubble over its handle on hover, focus and press, as the kit's track does. |
| label | — | — | Required. |
| helpText / errorText / warningText | — | — | Resolved through the shared field-message rule, so text and state cannot be shown apart. Error and warning put the value inputs in their states. |
| disabled | boolean | — | |
| readOnly | boolean | — | The value shows without a handle or the middle tick, and cannot be changed. |
Design tokens
Every swatch is live. Change the source color in the header and this table repaints, because it reads the same roles the component does.
on-surface-variantThe label (Text/text-secondary), and a range handle on hover (Icon/icon-secondary).on-surfaceThe bounds (Text/text-primary) and a range handle at rest (Icon/icon-primary).outlineThe single slider's rail and the middle tick, through the subtle step (Border/border-subtle-00).on-backgroundThe selected part of the rail and the single slider's handle (Border/border-inverse), and the value bubble's fill (Background/background-inverse).elevationThe range rail's ground, elevation-02 (Layer accent/layer-accent-01).primaryThe handle and the selected part on focus and press (Border/border-interactive, Miscellaneous/interactive), the focus and press ring through primary-focus, and the disabled family through primary-disabled and primary-disabled-content.backgroundThe gap inside a pressed handle's ring, and the value bubble's text (Icon/icon-inverse).dangerError text.textInput Label, Body/3, and Caption/1 in the bubble and the supporting text.radiusThe value bubble's 2px corner.spacingThe 16 and 8 gaps, and the bubble's padding.
Usage
The contract's prohibitions, written as the choices you will actually face.
Do
- Give it a label that names the value, such as “Opacity” or “Price range”.
- Keep the value inputs where an exact number matters; they are on by default.
- Use the range form to choose a band between two values.
- Say in the error text what the allowed range is.
Don’t
- Use a slider for a few discrete options. That is a Radio button group.
- Hide the bounds. They tell the reader what the ends of the track mean.
- Use it where only the exact number matters. That is a Text input.
- Restyle the value inputs. They are the governed Text input.
Accessibility
What the component does for you, and what it leaves to you.
- Roles
- A labelled group. Each handle is a native
input type="range", so its role, value and range are announced by the platform. A range names its handles “minimum” and “maximum” from the label. - Keyboard
- Arrow keys step by step; Page Up and Page Down by larger steps; Home and End go to the ends. The two range handles cannot cross.
- Inputs
- Each value input is named from the label, with the label hidden. Typing commits a value in range; leaving the field snaps to the nearest allowed value.
- Focus
- The handle grows and turns
--graphite-primary, with the fill; a range handle takes a 1px--graphite-primary-focusring. - Read-only
- The handles stay focusable and report
aria-readonly, but do not move.
Figma parity
The kit’s Slider page has two public sets, Slider and Slider - Range. The code is one component: a number is a Slider, a tuple is a range.
| Kit axis | Values | Code | How it maps |
|---|---|---|---|
| Set | Slider · Slider - Range | value | A number or a two-item tuple. |
| Inputs | True · False | showInputs | Range only in the kit; the code lets a single slider drop its input too. Off, a range shows its values in bubbles. |
| Status | Enabled · Hover · Focus · Active | — | Pseudo-classes of the native input (governance rule 7). |
| Status | Error · Warning | errorText, warningText | The value inputs take the state; the message goes under the row. |
| Status | Disabled · Read-only | disabled, readOnly | Read-only drops the handle and the tick, as the kit draws it. |
| Status | Skeleton | — | No counterpart by rule. |
| Handle | None · Left · Right | — | Which range handle is in play: the one under the pointer or focus. |
| Width | 288 input, 61 rail | — | The Slider set’s input hugs at 288 and squeezes its rail. The code uses the Range set’s 96 for every value input. |
