Slider
Pick a value or a range by dragging, tapping the track or using the keys, with jumps that glide and an optional value bubble.
pnpm dlx shadcn@latest add https://hextaui.com/r/slider.jsonAdds the component, the HextaUI theme tokens and any HextaUI components it depends on.
Add the theme tokens to your global CSS, if you haven’t yet.
Install the dependencies.
pnpm add @base-ui/react class-variance-authority cnCopy and paste the following code into your project.
components/ui/slider.tsx Update the import paths to match your project setup.
<Slider /> draws one thumb per value, so a number or a one-item array makes a single slider and two items make a range. Children such as <SliderLabel /> and <SliderValue /> sit on one line above the track.
While you drag, the thumb follows the pointer exactly. When the value jumps, from a press on the track, a key or a new controlled value, the thumb and fill glide there in 180ms instead of teleporting.
Sizes
sm, default and lg scale the thumb and track together.
Range
Pass two values for a range. Name each thumb with getAriaLabel, and keep them apart with minStepsBetweenValues. With draggableRange, drag anywhere between the thumbs to move both at once; a tap there still moves the nearest thumb.
Value bubble
showValue shows the formatted value above the thumb while it is dragged or focused from the keyboard. Use it instead of a label row, since the bubble rises into the space above the track.
Steps and format
step snaps the value, largeStep sets the Page Up and Shift + arrow jump, and format formats every number the slider shows or announces.
Controlled
onValueChange fires on every move and onValueCommitted once on release, which is the moment to save. Setting the value from outside glides too.
Vertical
With orientation="vertical" the slider fills its parent's height, and Up raises the value.
With icons
Place icons beside the slider in a flex row. The slider takes the remaining width.
Disabled
The whole slider dims and ignores pointer and keyboard input.
Long labels
Long labels wrap, and the value stays on the end.
Right to left
Inside a right-to-left parent the fill starts from the right and the arrow keys follow it. Pass locale for the reader's digits.
| Key | Action |
|---|---|
| Tab | Moves focus to the next thumb. |
| →↑ | Increases the value by one step. → decreases it in right-to-left. |
| ←↓ | Decreases the value by one step. ← increases it in right-to-left. |
| Shift + ArrowPage UpPage Down | Moves by largeStep. |
| Home | Sets the minimum, or the previous thumb's value in a range. |
| End | Sets the maximum, or the next thumb's value in a range. |
- Each thumb holds a native
input type="range", so it is asliderwith its own value, min and max. <SliderLabel />names every thumb. Without one,aria-labelon<Slider />is passed to the thumbs, not the wrapper, so the slider is never left unnamed. In a range, usegetAriaLabelto tell the thumbs apart.<SliderValue />and the value bubble are not announced on every change; the thumb already reports its value.- Pressing a thumb doesn't show a focus ring; the arrow keys do. With reduced motion the thumb jumps instead of gliding.
- On touch screens the hit area grows to at least 44px without changing the layout.
Built on the Base UI slider. Every part accepts the props of the primitive it wraps.
| Prop | Type | Default |
|---|---|---|
valueThe controlled value. One thumb per item. | number | number[] | – |
defaultValue | number | number[] | – |
onValueChangeFires on every change while dragging. | (value, eventDetails) => void | – |
onValueCommittedFires once when a change ends. | (value, eventDetails) => void | – |
min | number | 0 |
max | number | 100 |
step | number | 1 |
largeStep | number | 10 |
minStepsBetweenValues | number | 0 |
size | "sm" | "default" | "lg" | "default" |
orientation | "horizontal" | "vertical" | "horizontal" |
draggableRangeIn a range, dragging between the thumbs moves them together, keeping the gap. | boolean | false |
showValueShows the value above the thumb while dragging or keyboard-focused. | boolean | false |
thumbAlignmentedge keeps the thumb inside the track at min and max. | "edge" | "center" | "edge-client-only" | "edge" |
thumbCollisionBehavior | "push" | "swap" | "none" | "push" |
format | Intl.NumberFormatOptions | – |
locale | Intl.LocalesArgument | "en-US" |
aria-labelNames the thumbs. | string | – |
getAriaLabelNames each thumb of a range. | (index: number) => string | – |
getAriaValueText | (formattedValue: string, value: number, index: number) => string | – |
name | string | – |
disabled | boolean | false |
className | string | (state) => string | – |
render | ReactElement | (props, state) => ReactElement | <div> |
| Attribute | Description |
|---|---|
data-slot="slider" | The root. |
data-size | sm, default or lg. |
data-jump | Present for 220ms while the thumb glides to a new value. |
data-range-dragging | Present while the whole range is being dragged. |
data-orientation | horizontal or vertical. |
data-dragging | Present while a pointer is down. |
data-disabled | Present when disabled. |
data-invalid | Present when invalid inside a Field. |
--slider-thumb | The thumb's diameter, set by size. |
--slider-track | The track's thickness, set by size. |
data-slot="slider-control" | The pressable area around the track. |
data-slot="slider-track" | The track. |
data-slot="slider-range" | The fill between the start, or the first thumb, and the last thumb. |
data-slot="slider-thumb" | Each thumb. data-index gives its position. |
data-active | On the thumb that is focused or being dragged. |
data-slot="slider-thumb-value" | The value bubble from showValue. |
Names the thumbs and grows to fill the row. Renders a <div>.
| Prop | Type | Default |
|---|---|---|
render | ReactElement | (props, state) => ReactElement | <div> |
| Attribute | Description |
|---|---|
data-slot="slider-label" | The label. |
Shows the formatted values, joined with an en dash in a range. Renders an <output>.
| Prop | Type | Default |
|---|---|---|
childrenCustom text. | (formattedValues: string[], values: number[]) => ReactNode | – |
render | ReactElement | (props, state) => ReactElement | <output> |
| Attribute | Description |
|---|---|
data-slot="slider-value" | The value. |
data-orientation | horizontal or vertical. |
data-dragging | Present while a pointer is down. |
data-disabled | Present when disabled. |
data-invalid | Present when invalid inside a Field. |