Slider
A high-quality, unstyled React slider component that works like a range input and is easy to style.
An easily stylable range input.
Usage guidelines
- Form controls must have an accessible name: See Labeling a slider and the forms guide.
Anatomy
Import the component and assemble its parts:
import { Slider } from '@base-ui/react/slider';
<Slider.Root>
<Slider.Value />
<Slider.Control>
<Slider.Track>
<Slider.Indicator />
<Slider.Thumb />
</Slider.Track>
</Slider.Control>
</Slider.Root>;Examples
Range slider
To create a range slider:
- Pass an array of values and place a
<Slider.Thumb>for each value in the array - Additionally for server-side rendering, specify a numeric
indexfor each thumb that corresponds to the index of its value in the value array
Thumbs can be configured to behave differently when they collide during pointer interactions using the thumbCollisionBehavior prop on <Slider.Root>.
Thumb alignment
Set thumbAlignment="edge" to inset the thumb such that its edge aligns with the edge of the control when the value is at min or max, without overflowing the control like the default "center" alignment.
A client-only alternative thumbAlignment="edge-client-only" can be used to reduce bundle size but only renders after React hydration.
Labeling a slider
A single-thumb slider without a visible label (such as a volume control) can be labeled using aria-label on <Slider.Thumb>:
<Slider.Root>
<Slider.Control>
<Slider.Track>
<Slider.Indicator />
<Slider.Thumb aria-label="Volume" />
</Slider.Track>
</Slider.Control>
</Slider.Root>A visible label can be created using aria-labelledby on <Slider.Root> that references the id of a sibling element, such as a <div>:
<div id="volume-label">Volume</div>
<Slider.Root aria-labelledby="volume-label">
<Slider.Control>
<Slider.Track>
<Slider.Indicator />
<Slider.Thumb />
</Slider.Track>
</Slider.Control>
</Slider.Root>For a multi-thumb range slider with a visible label, add aria-label on each <Slider.Thumb> to distinguish them:
<div id="price-label">Price range</div>
<Slider.Root defaultValue={[25, 75]} aria-labelledby="price-label">
<Slider.Control>
<Slider.Track>
<Slider.Indicator />
<Slider.Thumb index={0} aria-label="Minimum price" />
<Slider.Thumb index={1} aria-label="Maximum price" />
</Slider.Track>
</Slider.Control>
</Slider.Root>The Field and Fieldset components can also be used to provide accessible labels for sliders, eliminating the need to track id or aria-labelledby associations manually. Field comes with a UX improvement to prevent double clicks from selecting the label text.
For a single-thumb slider, use Field to provide a visible label:
<Field.Root>
<Field.Label>Volume</Field.Label>
<Slider.Root>
<Slider.Control>
<Slider.Track>
<Slider.Indicator />
<Slider.Thumb />
</Slider.Track>
</Slider.Control>
</Slider.Root>
</Field.Root>For a multi-thumb range slider, use Fieldset by replacing the <Fieldset.Root> element with <Slider.Root> via the render prop. <Fieldset.Legend> provides the visible label for the group:
<Field.Root>
<Fieldset.Root render={<Slider.Root />}>
<Fieldset.Legend>Price range</Fieldset.Legend>
<Slider.Control>
<Slider.Track>
<Slider.Indicator />
<Slider.Thumb index={0} aria-label="Minimum price" />
<Slider.Thumb index={1} aria-label="Maximum price" />
</Slider.Track>
</Slider.Control>
</Fieldset.Root>
</Field.Root>Form integration
To use a slider in a form, pass the slider's name to <Field.Root>:
<Form>
<Field.Root name="volume">
<Field.Label>Volume</Field.Label>
<Slider.Root>
<Slider.Control>
<Slider.Track>
<Slider.Indicator />
<Slider.Thumb />
</Slider.Track>
</Slider.Control>
</Slider.Root>
</Field.Root>
</Form>API reference
Root
| Name | Type | Default | Description |
|---|---|---|---|
defaultValueOptional | Value | undefined | — | The uncontrolled value of the slider when it's initially rendered. To render a controlled slider, use the `value` prop instead. |
disabledOptional | boolean | undefined | false | Whether the slider should ignore user interaction. |
formatOptional | Intl.NumberFormatOptions | undefined | — | Options to format the input value. |
localeOptional | Intl.LocalesArgument | undefined | — | The locale used by `Intl.NumberFormat` when formatting the value. Defaults to the user's runtime locale. |
maxOptional | number | undefined | 100 | The maximum allowed value of the slider. Should not be equal to min. |
minOptional | number | undefined | 0 | The minimum allowed value of the slider. Should not be equal to max. |
minStepsBetweenValuesOptional | number | undefined | 0 | The minimum steps between values in a range slider. |
nameOptional | string | undefined | — | Identifies the field when a form is submitted. |
orientationOptional | Orientation | undefined | horizontal | The component orientation. |
stepOptional | number | 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. |
largeStepOptional | number | undefined | 10 | The granularity with which the slider can step through values when using Page Up/Page Down or Shift + Arrow Up/Arrow Down. |
thumbAlignmentOptional | '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 |
thumbCollisionBehaviorOptional | 'push' | 'swap' | 'none' | 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. |
valueOptional | Value | undefined | — | The value of the slider. For ranged sliders, provide an array with two values. |
valueRequired | Value extends number ? number : Value, | — | — |
eventDetailsRequired | SliderRoot.ChangeEventDetails, | — | — |
valueRequired | Value extends number ? number : Value, | — | — |
eventDetailsRequired | SliderRoot.CommitEventDetails, | — | — |
Thumb
| Name | Type | Default | Description |
|---|---|---|---|
disabledOptional | boolean | undefined | false | Whether the thumb should ignore user interaction. |
getAriaLabelOptional | ((index: number) => string) | null | undefined | — | A function which returns a string value for the [`aria-label`](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Reference/Attributes/aria-label) attribute of the `input`. |