Jone

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

Anatomy

Import the component and assemble its parts:

Anatomy
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:

  1. Pass an array of values and place a <Slider.Thumb> for each value in the array
  2. Additionally for server-side rendering, specify a numeric index for 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 with invisible label
<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>:

Slider with visible label
<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:

Labeling multi-thumb range sliders
<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:

Using Field to label a slider
<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:

Using Fieldset to label a multi-thumb slider
<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>:

Using Slider in a form
<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

NameTypeDefaultDescription
defaultValueOptionalValue | undefinedThe uncontrolled value of the slider when it's initially rendered. To render a controlled slider, use the `value` prop instead.
disabledOptionalboolean | undefinedfalseWhether the slider should ignore user interaction.
formatOptionalIntl.NumberFormatOptions | undefinedOptions to format the input value.
localeOptionalIntl.LocalesArgument | undefinedThe locale used by `Intl.NumberFormat` when formatting the value. Defaults to the user's runtime locale.
maxOptionalnumber | undefined100The maximum allowed value of the slider. Should not be equal to min.
minOptionalnumber | undefined0The minimum allowed value of the slider. Should not be equal to max.
minStepsBetweenValuesOptionalnumber | undefined0The minimum steps between values in a range slider.
nameOptionalstring | undefinedIdentifies the field when a form is submitted.
orientationOptionalOrientation | undefinedhorizontalThe component orientation.
stepOptionalnumber | undefined1The 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.
largeStepOptionalnumber | undefined10The 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' | undefinedcenterHow 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' | undefinedpushControls 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.
valueOptionalValue | undefinedThe value of the slider. For ranged sliders, provide an array with two values.
valueRequiredValue extends number ? number : Value,
eventDetailsRequiredSliderRoot.ChangeEventDetails,
valueRequiredValue extends number ? number : Value,
eventDetailsRequiredSliderRoot.CommitEventDetails,

Thumb

NameTypeDefaultDescription
disabledOptionalboolean | undefinedfalseWhether the thumb should ignore user interaction.
getAriaLabelOptional((index: number) => string) | null | undefinedA 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`.

On this page