Skip to main content
A slider component for selecting a value or range from a continuous spectrum.

Import

import { Slider } from '@base-ui/react/slider';

Anatomy

The Slider component consists of multiple parts:
  • Slider.Root - The container that manages slider state
  • Slider.Control - The track area that contains the slider
  • Slider.Track - Visual track showing the selected range
  • Slider.Thumb - Draggable handle for selecting values
  • Slider.Indicator - Visual indicator at specific positions
  • Slider.Value - Displays the current value

Basic Usage

<Slider.Root defaultValue={50}>
  <Slider.Control>
    <Slider.Track />
    <Slider.Thumb />
  </Slider.Control>
</Slider.Root>

Key Features

  • Single and range sliders
  • Controlled and uncontrolled modes
  • Min/max constraints
  • Step increments
  • Keyboard navigation
  • Horizontal and vertical orientation
  • Number formatting support
  • Accessible with proper ARIA attributes
  • Custom thumb alignment

Key Props

value

Type: number | readonly number[] The value of the slider. For range sliders, provide an array with two values. Use with onValueChange for controlled mode.
const [value, setValue] = React.useState(50);

<Slider.Root value={value} onValueChange={setValue}>
  <Slider.Control>
    <Slider.Track />
    <Slider.Thumb />
  </Slider.Control>
</Slider.Root>

defaultValue

Type: number | readonly number[] The uncontrolled value when initially rendered.
<Slider.Root defaultValue={25}>
  <Slider.Control>
    <Slider.Track />
    <Slider.Thumb />
  </Slider.Control>
</Slider.Root>

min

Type: number Default: 0 The minimum allowed value of the slider.

max

Type: number Default: 100 The maximum allowed value of the slider.
<Slider.Root min={0} max={100} defaultValue={50}>
  <Slider.Control>
    <Slider.Track />
    <Slider.Thumb />
  </Slider.Control>
</Slider.Root>

step

Type: number Default: 1 The granularity with which the slider can step through values.
<Slider.Root step={5} min={0} max={100}>
  <Slider.Control>
    <Slider.Track />
    <Slider.Thumb />
  </Slider.Control>
</Slider.Root>

largeStep

Type: number Default: 10 The step value when using Page Up/Page Down or Shift + Arrow keys.

orientation

Type: 'horizontal' | 'vertical' Default: 'horizontal' The component orientation.
<Slider.Root orientation="vertical">
  <Slider.Control>
    <Slider.Track />
    <Slider.Thumb />
  </Slider.Control>
</Slider.Root>

disabled

Type: boolean Default: false Whether the slider should ignore user interaction.

minStepsBetweenValues

Type: number Default: 0 The minimum steps between values in a range slider.

thumbAlignment

Type: 'center' | 'edge' | 'edge-client-only' Default: 'center' How the thumbs are aligned relative to the control when at min or max.

thumbCollisionBehavior

Type: 'push' | 'swap' | 'none' Default: 'push' Controls how thumbs behave when they collide during pointer interactions.

onValueChange

Type: (value: number | number[], eventDetails: ChangeEventDetails) => void Callback fired when the slider’s value changes.

onValueCommitted

Type: (value: number | number[], eventDetails: CommitEventDetails) => void Callback fired when the pointerup is triggered.

format

Type: Intl.NumberFormatOptions Options to format the input value.

Styling

<Slider.Root className="w-64">
  <Slider.Control className="relative h-2 bg-gray-200 rounded-full">
    <Slider.Track className="absolute h-full bg-blue-500 rounded-full" />
    <Slider.Thumb className="absolute w-5 h-5 -translate-y-1/2 bg-white border-2 border-blue-500 rounded-full shadow-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2" />
  </Slider.Control>
</Slider.Root>

Common Patterns

Range Slider

<Slider.Root defaultValue={[25, 75]}>
  <Slider.Control>
    <Slider.Track />
    <Slider.Thumb />
    <Slider.Thumb />
  </Slider.Control>
</Slider.Root>

With Value Display

<Slider.Root defaultValue={50}>
  <div className="flex justify-between mb-2">
    <label>Volume</label>
    <Slider.Value />
  </div>
  <Slider.Control>
    <Slider.Track />
    <Slider.Thumb />
  </Slider.Control>
</Slider.Root>

Vertical Slider

<Slider.Root orientation="vertical" defaultValue={50} className="h-64">
  <Slider.Control>
    <Slider.Track />
    <Slider.Thumb />
  </Slider.Control>
</Slider.Root>

Price Range Selector

function PriceRange() {
  const [range, setRange] = React.useState([100, 500]);

  return (
    <div>
      <div className="flex justify-between mb-2">
        <span>Price Range</span>
        <span>${range[0]} - ${range[1]}</span>
      </div>
      <Slider.Root
        value={range}
        onValueChange={setRange}
        min={0}
        max={1000}
        step={10}
      >
        <Slider.Control>
          <Slider.Track />
          <Slider.Thumb />
          <Slider.Thumb />
        </Slider.Control>
      </Slider.Root>
    </div>
  );
}

With Marks

function SliderWithMarks() {
  const marks = [0, 25, 50, 75, 100];

  return (
    <Slider.Root defaultValue={50}>
      <Slider.Control>
        <Slider.Track />
        {marks.map((mark) => (
          <Slider.Indicator key={mark} value={mark} className="absolute w-1 h-1 bg-gray-400 rounded-full" />
        ))}
        <Slider.Thumb />
      </Slider.Control>
      <div className="flex justify-between text-xs text-gray-500 mt-1">
        {marks.map((mark) => (
          <span key={mark}>{mark}</span>
        ))}
      </div>
    </Slider.Root>
  );
}

Temperature Control

function TemperatureSlider() {
  const [temp, setTemp] = React.useState(72);

  return (
    <div>
      <div className="text-center text-2xl font-bold mb-4">
        {temp}°F
      </div>
      <Slider.Root
        value={temp}
        onValueChange={setTemp}
        min={60}
        max={80}
        step={1}
      >
        <Slider.Control>
          <Slider.Track />
          <Slider.Thumb />
        </Slider.Control>
      </Slider.Root>
    </div>
  );
}