Theme
Customize appearance
Components
Slider
Adjust a numeric value by dragging or using the keyboard.
View component source ↗Preview
A minimal example to get started.
Volume: 40%
Installation
Install this component and its dependencies in a project initialized with shadcn.
pnpm dlx shadcn@latest add https://ui.hyunjoon.net/r/slider.jsonUsage
This is the basic example. Use the Code tab above for the selected example. Adjust import aliases to match your project.
import { useState } from "react";
import { Slider } from "@/components/ui/slider";
export default function Example() {
const [value, setValue] = useState([40]);
return (
<div className="w-64 space-y-4">
<Slider
value={value}
onValueChange={(next) => setValue(typeof next === "number" ? [next] : [...next])}
max={100}
aria-label="Volume"
/>
<p className="text-sm text-muted-foreground">Volume: {value[0]}%</p>
</div>
);
}
API reference
Derived from the installed component types. Native DOM props are also supported where applicable. A dash means no explicit default is documented. Some props depend on the selected mode.
Slider
| Prop | Type | Default | Description |
|---|---|---|---|
defaultValue | number | readonly number[] | undefinednumber | readonly number[] | undefined | — | The uncontrolled value of the slider when it's initially rendered. To render a controlled slider, use the `value` prop instead. |
disabled | boolean | undefinedboolean | undefined | false | Whether the slider should ignore user interaction. |
format | Intl.NumberFormatOptions | undefinedIntl.NumberFormatOptions | undefined | — | Options to format the input value. |
locale | Intl.LocalesArgumentIntl.LocalesArgument | — | The locale used by `Intl.NumberFormat` when formatting the value. Defaults to the user's runtime locale. |
max | number | undefinednumber | undefined | 100 | The maximum allowed value of the slider. Should not be equal to min. |
min | number | undefinednumber | undefined | 0 | The minimum allowed value of the slider. Should not be equal to max. |
minStepsBetweenValues | number | undefinednumber | undefined | 0 | The minimum steps between values in a range slider. |
name | string | undefinedstring | undefined | — | Identifies the field when a form is submitted. |
form | string | undefinedstring | undefined | — | Identifies the form that owns the slider inputs. Useful when the slider is rendered outside the form. |
orientation | Orientation | undefinedOrientation | undefined | 'horizontal' | The component orientation. |
step | number | undefinednumber | undefined | 1 | The granularity with which the slider can step through values. (A "discrete" slider.) The `min` prop serves as the origin for the valid values. We recommend (max - min) to be evenly divisible by the step. |
largeStep | number | undefinednumber | undefined | 10 | The granularity with which the slider can step through values when using Page Up/Page Down or Shift + Arrow Up/Arrow Down. |
thumbAlignment | "center" | "edge" | "edge-client-only" | undefined"center" | "edge" | "edge-client-only" | undefined | 'center' | How the thumb(s) are aligned relative to `Slider.Control` when the value is at `min` or `max`: - `center`: The center of the thumb is aligned with the control edge - `edge`: The thumb is inset within the control such that its edge is aligned with the control edge - `edge-client-only`: Same as `edge` but renders after React hydration on the client, reducing bundle size in return |
thumbCollisionBehavior | "none" | "push" | "swap" | undefined"none" | "push" | "swap" | undefined | 'push' | Controls how thumbs behave when they collide during pointer interactions. - `'push'` (default): Thumbs push each other without restoring their previous positions when dragged back. - `'swap'`: Thumbs swap places when dragged past each other. - `'none'`: Thumbs cannot move past each other; excess movement is ignored. |
value | number | readonly number[] | undefinednumber | readonly number[] | undefined | — | The value of the slider. For ranged sliders, provide an array with two values. |
onValueChange | ((value: number | readonly number[], eventDetails: SliderPrimitive.Root.ChangeEventDetails…((value: number | readonly number[], eventDetails: SliderPrimitive.Root.ChangeEventDetails) => void) | undefined | — | Callback function that is fired when the slider's value changed. You can pull out the new value by accessing `event.target.value` (any). The `eventDetails.reason` indicates what triggered the change: - `'input-change'` when the hidden range input emits a change event (for example, via form integration) - `'track-press'` when the control track is pressed - `'drag'` while dragging a thumb - `'keyboard'` for keyboard input - `'none'` when the change is triggered without a specific interaction |
onValueCommitted | ((value: number | readonly number[], eventDetails: SliderPrimitive.Root.CommitEventDetails…((value: number | readonly number[], eventDetails: SliderPrimitive.Root.CommitEventDetails) => void) | undefined | — | Callback function that is fired when the `pointerup` is triggered. **Warning**: This is a generic event not a change event. The `eventDetails.reason` indicates what triggered the commit: - `'drag'` while dragging a thumb - `'track-press'` when the control track is pressed - `'keyboard'` for keyboard input - `'input-change'` when the hidden range input emits a change event (for example, via form integration) - `'none'` when the commit occurs without a specific interaction |
ref | React.Ref<HTMLDivElement> | undefinedReact.Ref<HTMLDivElement> | undefined | — | Allows getting a ref to the component instance. Once the component unmounts, React will set `ref.current` to `null` (or call the ref with `null` if you passed a callback ref). |
id | string | undefinedstring | undefined | — | Unique identifier used to associate labels and descriptions. |
children | React.ReactNodeReact.ReactNode | — | Content rendered inside this component. |
onFocus | ((event: BaseUIEvent<React.FocusEvent<HTMLDivElement, Element>>) => void) | undefined((event: BaseUIEvent<React.FocusEvent<HTMLDivElement, Element>>) => void) | undefined | — | Called when the control receives focus. |
onBlur | ((event: BaseUIEvent<React.FocusEvent<HTMLDivElement, Element>>) => void) | undefined((event: BaseUIEvent<React.FocusEvent<HTMLDivElement, Element>>) => void) | undefined | — | Called when the control loses focus. |
onChange | ((event: BaseUIEvent<React.ChangeEvent<HTMLDivElement, Element>>) => void) | undefined((event: BaseUIEvent<React.ChangeEvent<HTMLDivElement, Element>>) => void) | undefined | — | Called when the underlying form control changes; inspect the event for its value. |
onKeyDown | ((event: BaseUIEvent<React.KeyboardEvent<HTMLDivElement>>) => void) | undefined((event: BaseUIEvent<React.KeyboardEvent<HTMLDivElement>>) => void) | undefined | — | Called when a key is pressed while this element is focused. |
onClick | ((event: BaseUIEvent<React.MouseEvent<HTMLDivElement, MouseEvent>>) => void) | undefined((event: BaseUIEvent<React.MouseEvent<HTMLDivElement, MouseEvent>>) => void) | undefined | — | Called when the element is activated. |
className | string | ((state: SliderRootState) => string | undefined) | undefinedstring | ((state: SliderRootState) => string | undefined) | undefined | — | CSS class applied to the element, or a function that returns a class based on the component's state. |
render | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | ComponentRenderFn…React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, SliderRootState> | undefined | — | Allows you to replace the component's HTML element with a different tag, or compose it with another component. Accepts a `ReactElement` or a function that returns the element to render. |
style | React.CSSProperties | ((state: SliderRootState) => React.CSSProperties | undefined) | unde…React.CSSProperties | ((state: SliderRootState) => React.CSSProperties | undefined) | undefined | — | Style applied to the element, or a function that returns a style object based on the component's state. |
Usage notes
Specify the minimum, maximum, and step for your range. Controlled values are arrays so the same component can represent multiple thumbs.