---
title: Slider
subtitle: An easily stylable range input.
description: A high-quality, unstyled React slider component that works like a range input and is easy to style.
---

> FineSoft Components documentation. Independent Stencil port; not the official Base UI website.
>
> React API text and `@base-ui/react` examples are upstream references. FineSoft Stencil examples use `finesoft-components`. Do not treat the two packages as interchangeable.

# Slider

A high-quality, unstyled React slider component that works like a range input and is easy to style.

## Demo

### Tailwind

This example shows how to implement the component using Tailwind CSS.

```tsx
/* docs-comparison.tsx */
import { StencilComparison } from 'docs/src/components/StencilComparison';
import ReactSlider from './react-slider';
import StencilSlider from './stencil-slider';

export default function DocsSliderComparison() {
  return <StencilComparison key="tailwind" component="slider" react={<ReactSlider />} stencil={<StencilSlider />} />;
}
```

```tsx
/* react-slider.tsx */
import { Slider } from '@base-ui/react/slider';

export default function ExampleSlider() {
  return (
    <Slider.Root defaultValue={25}>
      <Slider.Control className="flex w-56 touch-none items-center py-3 select-none">
        <Slider.Track className="h-1 w-full bg-neutral-200 select-none dark:bg-neutral-800">
          <Slider.Indicator className="bg-neutral-950 select-none dark:bg-white" />
          <Slider.Thumb
            aria-label="Volume"
            className="size-4 border border-neutral-950 bg-white select-none has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-neutral-950 dark:has-[:focus-visible]:outline-white dark:border-white dark:bg-neutral-950"
          />
        </Slider.Track>
      </Slider.Control>
    </Slider.Root>
  );
}
```

```tsx
/* stencil-slider.tsx */

export default function StencilSlider() {
  return (
    <fs-slider-root default-value={25}>
      <fs-slider-control className="flex w-56 touch-none items-center py-3 select-none">
        <fs-slider-track className="h-1 w-full bg-neutral-200 select-none dark:bg-neutral-800">
          <fs-slider-indicator className="bg-neutral-950 select-none dark:bg-white" />
          <fs-slider-thumb
            aria-label="Volume"
            className="size-4 border border-neutral-950 bg-white select-none has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-neutral-950 dark:has-[:focus-visible]:outline-white dark:border-white dark:bg-neutral-950"
          />
        </fs-slider-track>
      </fs-slider-control>
    </fs-slider-root>
  );
}
```

### CSS Modules

This example shows how to implement the component using CSS Modules.

```css
/* index.module.css */
.Control {
  box-sizing: border-box;
  display: flex;
  align-items: center;
  width: 14rem;
  padding-block: 0.75rem;
  touch-action: none;
  -webkit-user-select: none;
  user-select: none;
}

.Track {
  width: 100%;
  height: 0.25rem;
  background-color: oklch(92.2% 0 0deg);
  -webkit-user-select: none;
  user-select: none;

  @media (prefers-color-scheme: dark) {
    background-color: oklch(26.9% 0 0deg);
  }
}

.Indicator {
  background-color: oklch(14.5% 0 0deg);
  -webkit-user-select: none;
  user-select: none;

  @media (prefers-color-scheme: dark) {
    background-color: white;
  }
}

.Thumb {
  box-sizing: border-box;
  width: 1rem;
  height: 1rem;
  border: 1px solid oklch(14.5% 0 0deg);
  background-color: white;
  -webkit-user-select: none;
  user-select: none;

  @media (prefers-color-scheme: dark) {
    border: 1px solid white;
    background-color: oklch(14.5% 0 0deg);
  }

  &:has(:focus-visible) {
    outline: 2px solid oklch(14.5% 0 0deg);
    outline-offset: 2px;

    @media (prefers-color-scheme: dark) {
      outline-color: white;
    }
  }
}
```

```tsx
/* docs-comparison.tsx */
import { StencilComparison } from 'docs/src/components/StencilComparison';
import ReactSlider from './react-slider';
import StencilSlider from './stencil-slider';

export default function DocsSliderComparison() {
  return <StencilComparison key="css-modules" component="slider" react={<ReactSlider />} stencil={<StencilSlider />} />;
}
```

```tsx
/* react-slider.tsx */
import { Slider } from '@base-ui/react/slider';
import styles from './index.module.css';

export default function ExampleSlider() {
  return (
    <Slider.Root defaultValue={25}>
      <Slider.Control className={styles.Control}>
        <Slider.Track className={styles.Track}>
          <Slider.Indicator className={styles.Indicator} />
          <Slider.Thumb aria-label="Volume" className={styles.Thumb} />
        </Slider.Track>
      </Slider.Control>
    </Slider.Root>
  );
}
```

```tsx
/* stencil-slider.tsx */
export default function StencilSlider() {
  return (
    <fs-slider-root default-value={25}>
      <fs-slider-control>
        <fs-slider-track>
          <fs-slider-indicator />
          <fs-slider-thumb aria-label="Volume" />
        </fs-slider-track>
      </fs-slider-control>
    </fs-slider-root>
  );
}
```

## Stencil boundary

All seven Stencil Parts keep Light DOM. Root, Control, Track, Indicator, and Label
use their public hosts for layout, measurement, state, and semantics. Thumb keeps
its native range input in the same tree as labels and forms; Value keeps a native
`output` whose `for` references those inputs. There are no public CSS parts.

Host classes and inline styles remain supported, and ordinary selectors can reach
the native input and output. The Base UI theme is built in; select `data-fs-theme="base-ui"` on an ancestor for the optional skin; use the
`--fs-slider-*` variables to customize it. Consumer layout and native form/ARIA
relationships are preserved without adding a Shadow wrapper.

## Usage guidelines

- **Form controls must have an accessible name**: Prefer `<Slider.Label>`, or provide an `aria-label` on each `<Slider.Thumb>` when no visible label is rendered. See [Labeling a slider](/react/components/slider.md) and the [forms guide](/react/handbook/forms.md).

## Anatomy

Import the component and assemble its parts:

```jsx title="Anatomy"
import { Slider } from '@base-ui/react/slider';

<Slider.Root>
  <Slider.Label />
  <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>`.

## Demo

### Tailwind

This example shows how to implement the component using Tailwind CSS.

```tsx
/* docs-comparison.tsx */
import { StencilComparison } from 'docs/src/components/StencilComparison';
import ReactSlider from './react-slider';
import StencilSlider from './stencil-slider';

export default function DocsSliderComparison() {
  return <StencilComparison key="tailwind" component="slider" react={<ReactSlider />} stencil={<StencilSlider />} />;
}
```

```tsx
/* react-slider.tsx */
import { Slider } from '@base-ui/react/slider';

export default function RangeSlider() {
  return (
    <Slider.Root defaultValue={[25, 45]}>
      <Slider.Control className="flex w-56 touch-none items-center py-3 select-none">
        <Slider.Track className="h-1 w-full bg-neutral-200 select-none dark:bg-neutral-800">
          <Slider.Indicator className="bg-neutral-950 select-none dark:bg-white" />
          <Slider.Thumb
            index={0}
            aria-label="Minimum value"
            className="size-4 border border-neutral-950 bg-white select-none has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-neutral-950 dark:has-[:focus-visible]:outline-white dark:border-white dark:bg-neutral-950"
          />
          <Slider.Thumb
            index={1}
            aria-label="Maximum value"
            className="size-4 border border-neutral-950 bg-white select-none has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-neutral-950 dark:has-[:focus-visible]:outline-white dark:border-white dark:bg-neutral-950"
          />
        </Slider.Track>
      </Slider.Control>
    </Slider.Root>
  );
}
```

```tsx
/* stencil-slider.tsx */

export default function StencilSlider() {
  return (
    <fs-slider-root default-value="[25,45]">
      <fs-slider-control className="flex w-56 touch-none items-center py-3 select-none">
        <fs-slider-track className="h-1 w-full bg-neutral-200 select-none dark:bg-neutral-800">
          <fs-slider-indicator className="bg-neutral-950 select-none dark:bg-white" />
          <fs-slider-thumb
            index={0}
            aria-label="Minimum value"
            className="size-4 border border-neutral-950 bg-white select-none has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-neutral-950 dark:has-[:focus-visible]:outline-white dark:border-white dark:bg-neutral-950"
          />
          <fs-slider-thumb
            index={1}
            aria-label="Maximum value"
            className="size-4 border border-neutral-950 bg-white select-none has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-neutral-950 dark:has-[:focus-visible]:outline-white dark:border-white dark:bg-neutral-950"
          />
        </fs-slider-track>
      </fs-slider-control>
    </fs-slider-root>
  );
}
```

### CSS Modules

This example shows how to implement the component using CSS Modules.

```css
/* index.module.css */
.Control {
  box-sizing: border-box;
  display: flex;
  align-items: center;
  width: 14rem;
  padding-block: 0.75rem;
  touch-action: none;
  -webkit-user-select: none;
  user-select: none;
}

.Track {
  width: 100%;
  height: 0.25rem;
  background-color: oklch(92.2% 0 0deg);
  -webkit-user-select: none;
  user-select: none;

  @media (prefers-color-scheme: dark) {
    background-color: oklch(26.9% 0 0deg);
  }
}

.Indicator {
  background-color: oklch(14.5% 0 0deg);
  -webkit-user-select: none;
  user-select: none;

  @media (prefers-color-scheme: dark) {
    background-color: white;
  }
}

.Thumb {
  box-sizing: border-box;
  width: 1rem;
  height: 1rem;
  border: 1px solid oklch(14.5% 0 0deg);
  background-color: white;
  -webkit-user-select: none;
  user-select: none;

  @media (prefers-color-scheme: dark) {
    border: 1px solid white;
    background-color: oklch(14.5% 0 0deg);
  }

  &:has(:focus-visible) {
    outline: 2px solid oklch(14.5% 0 0deg);
    outline-offset: 2px;

    @media (prefers-color-scheme: dark) {
      outline-color: white;
    }
  }
}
```

```tsx
/* docs-comparison.tsx */
import { StencilComparison } from 'docs/src/components/StencilComparison';
import ReactSlider from './react-slider';
import StencilSlider from './stencil-slider';

export default function DocsSliderComparison() {
  return <StencilComparison key="css-modules" component="slider" react={<ReactSlider />} stencil={<StencilSlider />} />;
}
```

```tsx
/* react-slider.tsx */
import { Slider } from '@base-ui/react/slider';
import styles from './index.module.css';

export default function RangeSlider() {
  return (
    <Slider.Root defaultValue={[25, 45]}>
      <Slider.Control className={styles.Control}>
        <Slider.Track className={styles.Track}>
          <Slider.Indicator className={styles.Indicator} />
          <Slider.Thumb index={0} aria-label="Minimum value" className={styles.Thumb} />
          <Slider.Thumb index={1} aria-label="Maximum value" className={styles.Thumb} />
        </Slider.Track>
      </Slider.Control>
    </Slider.Root>
  );
}
```

```tsx
/* stencil-slider.tsx */
export default function StencilSlider() {
  return (
    <fs-slider-root default-value="[25,45]">
      <fs-slider-control>
        <fs-slider-track>
          <fs-slider-indicator />
          <fs-slider-thumb index={0} aria-label="Minimum value" />
          <fs-slider-thumb index={1} aria-label="Maximum value" />
        </fs-slider-track>
      </fs-slider-control>
    </fs-slider-root>
  );
}
```

### Steps

Use the `step` prop to snap the value to multiples of a given increment, and `largeStep` to control the increment when using Page Up/Page Down or Shift + Arrow Up/Arrow Down.

## Demo

### Tailwind

This example shows how to implement the component using Tailwind CSS.

```tsx
/* docs-comparison.tsx */
import { StencilComparison } from 'docs/src/components/StencilComparison';
import ReactSlider from './react-slider';
import StencilSlider from './stencil-slider';

export default function DocsSliderComparison() {
  return <StencilComparison key="tailwind" component="slider" react={<ReactSlider />} stencil={<StencilSlider />} />;
}
```

```tsx
/* react-slider.tsx */
import { Slider } from '@base-ui/react/slider';

export default function StepsSlider() {
  return (
    <Slider.Root className="grid w-56 grid-cols-2" defaultValue={400} min={100} max={900} step={100} largeStep={200}>
      <Slider.Label className="text-sm text-neutral-950 dark:text-white">Playback speed</Slider.Label>
      <Slider.Value className="text-end text-sm text-neutral-950 dark:text-white" />
      <Slider.Control className="col-span-2 flex touch-none items-center py-3 select-none">
        <Slider.Track className="h-1 w-full bg-neutral-200 select-none dark:bg-neutral-800">
          <Slider.Indicator className="bg-neutral-950 select-none dark:bg-white" />
          <Slider.Thumb
            aria-label="Playback speed"
            className="size-4 border border-neutral-950 bg-white select-none has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-neutral-950 dark:has-[:focus-visible]:outline-white dark:border-white dark:bg-neutral-950"
          />
        </Slider.Track>
      </Slider.Control>
    </Slider.Root>
  );
}
```

```tsx
/* stencil-slider.tsx */
export default function StencilSlider() {
  return (
    <fs-slider-root className="grid w-56 grid-cols-2" default-value={400} min={100} max={900} step={100} large-step={200}>
      <fs-slider-label className="text-sm text-neutral-950 dark:text-white">Playback speed</fs-slider-label>
      <fs-slider-value className="text-end text-sm text-neutral-950 dark:text-white" />
      <fs-slider-control className="col-span-2 flex touch-none items-center py-3 select-none">
        <fs-slider-track className="h-1 w-full bg-neutral-200 select-none dark:bg-neutral-800">
          <fs-slider-indicator className="bg-neutral-950 select-none dark:bg-white" />
          <fs-slider-thumb
            aria-label="Playback speed"
            className="size-4 border border-neutral-950 bg-white select-none has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-neutral-950 dark:has-[:focus-visible]:outline-white dark:border-white dark:bg-neutral-950"
          />
        </fs-slider-track>
      </fs-slider-control>
    </fs-slider-root>
  );
}
```

### CSS Modules

This example shows how to implement the component using CSS Modules.

```css
/* index.module.css */
.Root {
  display: grid;
  grid-template-columns: 1fr 1fr;
  width: 14rem;
}

.Label {
  font-size: 0.875rem;
  line-height: 1.25rem;
  color: oklch(14.5% 0 0deg);

  @media (prefers-color-scheme: dark) {
    color: white;
  }
}

.Value {
  font-size: 0.875rem;
  line-height: 1.25rem;
  text-align: end;
  color: oklch(14.5% 0 0deg);

  @media (prefers-color-scheme: dark) {
    color: white;
  }
}

.Control {
  box-sizing: border-box;
  display: flex;
  grid-column: span 2;
  align-items: center;
  padding-block: 0.75rem;
  touch-action: none;
  -webkit-user-select: none;
  user-select: none;
}

.Track {
  width: 100%;
  height: 0.25rem;
  background-color: oklch(92.2% 0 0deg);
  -webkit-user-select: none;
  user-select: none;

  @media (prefers-color-scheme: dark) {
    background-color: oklch(26.9% 0 0deg);
  }
}

.Indicator {
  background-color: oklch(14.5% 0 0deg);
  -webkit-user-select: none;
  user-select: none;

  @media (prefers-color-scheme: dark) {
    background-color: white;
  }
}

.Thumb {
  box-sizing: border-box;
  width: 1rem;
  height: 1rem;
  border: 1px solid oklch(14.5% 0 0deg);
  background-color: white;
  -webkit-user-select: none;
  user-select: none;

  @media (prefers-color-scheme: dark) {
    border: 1px solid white;
    background-color: oklch(14.5% 0 0deg);
  }

  &:has(:focus-visible) {
    outline: 2px solid oklch(14.5% 0 0deg);
    outline-offset: 2px;

    @media (prefers-color-scheme: dark) {
      outline-color: white;
    }
  }
}
```

```tsx
/* docs-comparison.tsx */
import { StencilComparison } from 'docs/src/components/StencilComparison';
import ReactSlider from './react-slider';
import StencilSlider from './stencil-slider';

export default function DocsSliderComparison() {
  return <StencilComparison key="css-modules" component="slider" react={<ReactSlider />} stencil={<StencilSlider />} />;
}
```

```tsx
/* react-slider.tsx */
import { Slider } from '@base-ui/react/slider';
import styles from './index.module.css';

export default function StepsSlider() {
  return (
    <Slider.Root className={styles.Root} defaultValue={400} min={100} max={900} step={100} largeStep={200}>
      <Slider.Label className={styles.Label}>Font weight</Slider.Label>
      <Slider.Value className={styles.Value} />
      <Slider.Control className={styles.Control}>
        <Slider.Track className={styles.Track}>
          <Slider.Indicator className={styles.Indicator} />
          <Slider.Thumb aria-label="Font weight" className={styles.Thumb} />
        </Slider.Track>
      </Slider.Control>
    </Slider.Root>
  );
}
```

```tsx
/* stencil-slider.tsx */
export default function StencilSlider() {
  return (
    <fs-slider-root default-value={400} min={100} max={900} step={100} large-step={200}>
      <fs-slider-label>Font weight</fs-slider-label>
      <fs-slider-value />
      <fs-slider-control>
        <fs-slider-track>
          <fs-slider-indicator />
          <fs-slider-thumb aria-label="Font weight" />
        </fs-slider-track>
      </fs-slider-control>
    </fs-slider-root>
  );
}
```

### Marks

Render your own tick marks, positioning each mark along the track as a percentage of the value range.

## Demo

### Tailwind

This example shows how to implement the component using Tailwind CSS.

```tsx
/* docs-comparison.tsx */
import { StencilComparison } from 'docs/src/components/StencilComparison';
import ReactSlider from './react-slider';
import StencilSlider from './stencil-slider';

export default function DocsSliderComparison() {
  return <StencilComparison key="tailwind" component="slider" react={<ReactSlider />} stencil={<StencilSlider />} />;
}
```

```tsx
/* react-slider.tsx */
import { Slider } from '@base-ui/react/slider';

const MIN = 0;
const MAX = 100;
const MARKS = [0, 25, 50, 75, 100];

export default function MarksSlider() {
  return (
    <Slider.Root className="w-56" defaultValue={40} min={MIN} max={MAX}>
      <Slider.Control className="flex touch-none items-center py-2.5 select-none">
        <Slider.Track className="h-1 w-full bg-neutral-200 select-none dark:bg-neutral-800">
          <Slider.Indicator className="bg-neutral-950 select-none dark:bg-white" />
          {MARKS.map(mark => (
            <div
              key={mark}
              aria-hidden
              className="absolute top-1/2 h-2 w-px -translate-x-1/2 -translate-y-1/2 bg-neutral-950 dark:bg-white"
              style={{ left: `${valueToPercent(mark)}%` }}
            />
          ))}
          <Slider.Thumb
            aria-label="Volume"
            className="size-4 border border-neutral-950 bg-white select-none has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-neutral-950 dark:has-[:focus-visible]:outline-white dark:border-white dark:bg-neutral-950"
          />
        </Slider.Track>
      </Slider.Control>
      <div className="relative h-4 select-none" aria-hidden>
        {MARKS.map(mark => (
          <span key={mark} className="absolute -translate-x-1/2 text-xs whitespace-nowrap text-neutral-600 dark:text-neutral-400" style={{ left: `${valueToPercent(mark)}%` }}>
            {mark}
          </span>
        ))}
      </div>
    </Slider.Root>
  );
}

function valueToPercent(value: number) {
  return ((value - MIN) / (MAX - MIN)) * 100;
}
```

```tsx
/* stencil-slider.tsx */
const MIN = 0;
const MAX = 100;
const MARKS = [0, 25, 50, 75, 100];

export default function StencilSlider() {
  return (
    <fs-slider-root className="w-56" default-value={40} min={MIN} max={MAX}>
      <fs-slider-control className="flex touch-none items-center py-2.5 select-none">
        <fs-slider-track className="h-1 w-full bg-neutral-200 select-none dark:bg-neutral-800">
          <fs-slider-indicator className="bg-neutral-950 select-none dark:bg-white" />
          {MARKS.map(mark => (
            <div
              key={mark}
              aria-hidden
              className="absolute top-1/2 h-2 w-px -translate-x-1/2 -translate-y-1/2 bg-neutral-950 dark:bg-white"
              style={{ left: `${valueToPercent(mark)}%` }}
            />
          ))}
          <fs-slider-thumb
            aria-label="Volume"
            className="size-4 border border-neutral-950 bg-white select-none has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-neutral-950 dark:has-[:focus-visible]:outline-white dark:border-white dark:bg-neutral-950"
          />
        </fs-slider-track>
      </fs-slider-control>
      <div className="relative h-4 select-none" aria-hidden>
        {MARKS.map(mark => (
          <span key={mark} className="absolute -translate-x-1/2 text-xs whitespace-nowrap text-neutral-600 dark:text-neutral-400" style={{ left: `${valueToPercent(mark)}%` }}>
            {mark}
          </span>
        ))}
      </div>
    </fs-slider-root>
  );
}

function valueToPercent(value: number) {
  return ((value - MIN) / (MAX - MIN)) * 100;
}
```

### CSS Modules

This example shows how to implement the component using CSS Modules.

```css
/* index.module.css */
.Root {
  width: 14rem;
}

.Control {
  box-sizing: border-box;
  display: flex;
  align-items: center;
  padding-block: 0.625rem;
  touch-action: none;
  -webkit-user-select: none;
  user-select: none;
}

.Track {
  width: 100%;
  height: 0.25rem;
  background-color: oklch(92.2% 0 0deg);
  -webkit-user-select: none;
  user-select: none;

  @media (prefers-color-scheme: dark) {
    background-color: oklch(26.9% 0 0deg);
  }
}

.Indicator {
  background-color: oklch(14.5% 0 0deg);
  -webkit-user-select: none;
  user-select: none;

  @media (prefers-color-scheme: dark) {
    background-color: white;
  }
}

.Thumb {
  box-sizing: border-box;
  width: 1rem;
  height: 1rem;
  border: 1px solid oklch(14.5% 0 0deg);
  background-color: white;
  -webkit-user-select: none;
  user-select: none;

  @media (prefers-color-scheme: dark) {
    border: 1px solid white;
    background-color: oklch(14.5% 0 0deg);
  }

  &:has(:focus-visible) {
    outline: 2px solid oklch(14.5% 0 0deg);
    outline-offset: 2px;

    @media (prefers-color-scheme: dark) {
      outline-color: white;
    }
  }
}

.Mark {
  position: absolute;
  top: 50%;
  width: 1px;
  height: 0.5rem;
  background-color: oklch(14.5% 0 0deg);
  transform: translate(-50%, -50%);

  @media (prefers-color-scheme: dark) {
    background-color: white;
  }
}

.MarkLabels {
  position: relative;
  height: 1rem;
  -webkit-user-select: none;
  user-select: none;
}

.MarkLabel {
  position: absolute;
  top: 0;
  font-size: 0.75rem;
  line-height: 1rem;
  color: oklch(43.9% 0 0deg);
  white-space: nowrap;
  transform: translateX(-50%);

  @media (prefers-color-scheme: dark) {
    color: oklch(70.8% 0 0deg);
  }
}
```

```tsx
/* docs-comparison.tsx */
import { StencilComparison } from 'docs/src/components/StencilComparison';
import ReactSlider from './react-slider';
import StencilSlider from './stencil-slider';

export default function DocsSliderComparison() {
  return <StencilComparison key="css-modules" component="slider" react={<ReactSlider />} stencil={<StencilSlider />} />;
}
```

```tsx
/* react-slider.tsx */
import { Slider } from '@base-ui/react/slider';
import styles from './index.module.css';

const MIN = 0;
const MAX = 100;
const MARKS = [0, 25, 50, 75, 100];

export default function MarksSlider() {
  return (
    <Slider.Root className={styles.Root} defaultValue={40} min={MIN} max={MAX}>
      <Slider.Control className={styles.Control}>
        <Slider.Track className={styles.Track}>
          <Slider.Indicator className={styles.Indicator} />
          {MARKS.map(mark => (
            <div key={mark} aria-hidden className={styles.Mark} style={{ left: `${valueToPercent(mark)}%` }} />
          ))}
          <Slider.Thumb aria-label="Volume" className={styles.Thumb} />
        </Slider.Track>
      </Slider.Control>
      <div className={styles.MarkLabels} aria-hidden>
        {MARKS.map(mark => (
          <span key={mark} className={styles.MarkLabel} style={{ left: `${valueToPercent(mark)}%` }}>
            {mark}
          </span>
        ))}
      </div>
    </Slider.Root>
  );
}

function valueToPercent(value: number) {
  return ((value - MIN) / (MAX - MIN)) * 100;
}
```

```tsx
/* stencil-slider.tsx */
import './stencil.css';

const MIN = 0;
const MAX = 100;
const MARKS = [0, 25, 50, 75, 100];

export default function StencilSlider() {
  return (
    <fs-slider-root default-value={40} min={MIN} max={MAX}>
      <fs-slider-control className="demo-slider-marks-control">
        <fs-slider-track>
          <fs-slider-indicator />
          {MARKS.map(mark => (
            <div key={mark} aria-hidden className="demo-slider-marks-mark" style={{ left: `${valueToPercent(mark)}%` }} />
          ))}
          <fs-slider-thumb aria-label="Volume" />
        </fs-slider-track>
      </fs-slider-control>
      <div className="demo-slider-marks-mark-labels" aria-hidden>
        {MARKS.map(mark => (
          <span key={mark} className="demo-slider-marks-mark-label" style={{ left: `${valueToPercent(mark)}%` }}>
            {mark}
          </span>
        ))}
      </div>
    </fs-slider-root>
  );
}

function valueToPercent(value: number) {
  return ((value - MIN) / (MAX - MIN)) * 100;
}
```

```css
/* stencil.css */
/* Example layout and visual exceptions. Default component styles come from the theme. */
@layer fs-theme {
  .demo-slider-marks-control {
    padding-block: var(--fs-space-2-5);
  }

  .demo-slider-marks-mark {
    position: absolute;
    top: 50%;
    width: 1px;
    height: 0.5rem;
    background-color: var(--fs-color-foreground);
    transform: translate(-50%, -50%);
  }

  .demo-slider-marks-mark-labels {
    position: relative;
    height: 1rem;
    -webkit-user-select: none;
    user-select: none;
  }

  .demo-slider-marks-mark-label {
    position: absolute;
    top: 0;
    font-size: 0.75rem;
    line-height: 1rem;
    color: var(--fs-color-secondary);
    white-space: nowrap;
    transform: translateX(-50%);
  }
}
```

Marks are independent of the value's granularity—pair them with the [`step`](/react/components/slider.md) prop to snap the thumb to each mark.

### 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.

## Demo

### Tailwind

This example shows how to implement the component using Tailwind CSS.

```tsx
/* docs-comparison.tsx */
import { StencilComparison } from 'docs/src/components/StencilComparison';
import ReactSlider from './react-slider';
import StencilSlider from './stencil-slider';

export default function DocsSliderComparison() {
  return <StencilComparison key="tailwind" component="slider" react={<ReactSlider />} stencil={<StencilSlider />} />;
}
```

```tsx
/* react-slider.tsx */
import { Slider } from '@base-ui/react/slider';

export default function EdgeAlignedThumb() {
  return (
    <Slider.Root thumbAlignment="edge" defaultValue={25}>
      <Slider.Control className="flex w-56 touch-none items-center py-3 select-none">
        <Slider.Track className="h-1 w-full bg-neutral-200 select-none dark:bg-neutral-800">
          <Slider.Indicator className="bg-neutral-950 select-none dark:bg-white" />
          <Slider.Thumb
            aria-label="Volume"
            className="size-4 border border-neutral-950 bg-white select-none has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-neutral-950 dark:has-[:focus-visible]:outline-white dark:border-white dark:bg-neutral-950"
          />
        </Slider.Track>
      </Slider.Control>
    </Slider.Root>
  );
}
```

```tsx
/* stencil-slider.tsx */

export default function StencilSlider() {
  return (
    <fs-slider-root thumb-alignment="edge" default-value={25}>
      <fs-slider-control className="flex w-56 touch-none items-center py-3 select-none">
        <fs-slider-track className="h-1 w-full bg-neutral-200 select-none dark:bg-neutral-800">
          <fs-slider-indicator className="bg-neutral-950 select-none dark:bg-white" />
          <fs-slider-thumb
            aria-label="Volume"
            className="size-4 border border-neutral-950 bg-white select-none has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-neutral-950 dark:has-[:focus-visible]:outline-white dark:border-white dark:bg-neutral-950"
          />
        </fs-slider-track>
      </fs-slider-control>
    </fs-slider-root>
  );
}
```

### CSS Modules

This example shows how to implement the component using CSS Modules.

```css
/* index.module.css */
.Control {
  box-sizing: border-box;
  display: flex;
  align-items: center;
  width: 14rem;
  padding-block: 0.75rem;
  touch-action: none;
  -webkit-user-select: none;
  user-select: none;
}

.Track {
  width: 100%;
  height: 0.25rem;
  background-color: oklch(92.2% 0 0deg);
  -webkit-user-select: none;
  user-select: none;

  @media (prefers-color-scheme: dark) {
    background-color: oklch(26.9% 0 0deg);
  }
}

.Indicator {
  background-color: oklch(14.5% 0 0deg);
  -webkit-user-select: none;
  user-select: none;

  @media (prefers-color-scheme: dark) {
    background-color: white;
  }
}

.Thumb {
  box-sizing: border-box;
  width: 1rem;
  height: 1rem;
  border: 1px solid oklch(14.5% 0 0deg);
  background-color: white;
  -webkit-user-select: none;
  user-select: none;

  @media (prefers-color-scheme: dark) {
    border: 1px solid white;
    background-color: oklch(14.5% 0 0deg);
  }

  &:has(:focus-visible) {
    outline: 2px solid oklch(14.5% 0 0deg);
    outline-offset: 2px;

    @media (prefers-color-scheme: dark) {
      outline-color: white;
    }
  }
}
```

```tsx
/* docs-comparison.tsx */
import { StencilComparison } from 'docs/src/components/StencilComparison';
import ReactSlider from './react-slider';
import StencilSlider from './stencil-slider';

export default function DocsSliderComparison() {
  return <StencilComparison key="css-modules" component="slider" react={<ReactSlider />} stencil={<StencilSlider />} />;
}
```

```tsx
/* react-slider.tsx */
import { Slider } from '@base-ui/react/slider';
import styles from './index.module.css';

export default function EdgeAlignedThumb() {
  return (
    <Slider.Root thumbAlignment="edge" defaultValue={25}>
      <Slider.Control className={styles.Control}>
        <Slider.Track className={styles.Track}>
          <Slider.Indicator className={styles.Indicator} />
          <Slider.Thumb aria-label="Volume" className={styles.Thumb} />
        </Slider.Track>
      </Slider.Control>
    </Slider.Root>
  );
}
```

```tsx
/* stencil-slider.tsx */
export default function StencilSlider() {
  return (
    <fs-slider-root thumb-alignment="edge" default-value={25}>
      <fs-slider-control>
        <fs-slider-track>
          <fs-slider-indicator />
          <fs-slider-thumb aria-label="Volume" />
        </fs-slider-track>
      </fs-slider-control>
    </fs-slider-root>
  );
}
```

### 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>`:

```tsx title="Slider with invisible label"
<Slider.Root>
  <Slider.Control>
    <Slider.Track>
      <Slider.Indicator />
      {/* @highlight */}
      <Slider.Thumb aria-label="Volume" />
    </Slider.Track>
  </Slider.Control>
</Slider.Root>
```

A visible label can be created using `<Slider.Label>`:

```tsx title="Slider with visible label"
<Slider.Root>
  {/* @highlight */}
  <Slider.Label>Volume</Slider.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:

```tsx title="Labeling multi-thumb range sliders"
<Slider.Root defaultValue={[25, 75]}>
  <Slider.Label>Price range</Slider.Label>
  <Slider.Control>
    <Slider.Track>
      <Slider.Indicator />
      {/* @highlight-start */}
      <Slider.Thumb index={0} aria-label="Minimum price" />
      <Slider.Thumb index={1} aria-label="Maximum price" />
      {/* @highlight-end */}
    </Slider.Track>
  </Slider.Control>
</Slider.Root>
```

### Vertical

Set `orientation="vertical"` on `<Slider.Root>` to build a vertical slider.

## Demo

### Tailwind

This example shows how to implement the component using Tailwind CSS.

```tsx
/* docs-comparison.tsx */
import { StencilComparison } from 'docs/src/components/StencilComparison';
import ReactSlider from './react-slider';
import StencilSlider from './stencil-slider';

export default function DocsSliderComparison() {
  return <StencilComparison key="tailwind" component="slider" react={<ReactSlider />} stencil={<StencilSlider />} />;
}
```

```tsx
/* react-slider.tsx */
import { Slider } from '@base-ui/react/slider';

export default function VerticalSlider() {
  return (
    <Slider.Root orientation="vertical" defaultValue={35}>
      <Slider.Control className="flex touch-none select-none data-[orientation=vertical]:h-32 data-[orientation=vertical]:px-3">
        <Slider.Track className="bg-neutral-200 select-none dark:bg-neutral-800 data-[orientation=vertical]:h-full data-[orientation=vertical]:w-1">
          <Slider.Indicator className="bg-neutral-950 select-none dark:bg-white" />
          <Slider.Thumb
            aria-label="Volume"
            className="size-4 border border-neutral-950 bg-white select-none has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-neutral-950 dark:has-[:focus-visible]:outline-white dark:border-white dark:bg-neutral-950"
          />
        </Slider.Track>
      </Slider.Control>
    </Slider.Root>
  );
}
```

```tsx
/* stencil-slider.tsx */

export default function StencilSlider() {
  return (
    <fs-slider-root orientation="vertical" default-value={35}>
      <fs-slider-control className="flex touch-none select-none data-[orientation=vertical]:h-32 data-[orientation=vertical]:px-3">
        <fs-slider-track className="bg-neutral-200 select-none dark:bg-neutral-800 data-[orientation=vertical]:h-full data-[orientation=vertical]:w-1">
          <fs-slider-indicator className="bg-neutral-950 select-none dark:bg-white" />
          <fs-slider-thumb
            aria-label="Volume"
            className="size-4 border border-neutral-950 bg-white select-none has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-neutral-950 dark:has-[:focus-visible]:outline-white dark:border-white dark:bg-neutral-950"
          />
        </fs-slider-track>
      </fs-slider-control>
    </fs-slider-root>
  );
}
```

### CSS Modules

This example shows how to implement the component using CSS Modules.

```css
/* index.module.css */
.Control {
  box-sizing: border-box;
  display: flex;
  touch-action: none;
  -webkit-user-select: none;
  user-select: none;

  &[data-orientation='vertical'] {
    height: 8rem;
    padding-inline: 0.75rem;
  }
}

.Track {
  background-color: oklch(92.2% 0 0deg);
  -webkit-user-select: none;
  user-select: none;

  @media (prefers-color-scheme: dark) {
    background-color: oklch(26.9% 0 0deg);
  }

  &[data-orientation='vertical'] {
    height: 100%;
    width: 0.25rem;
  }
}

.Indicator {
  background-color: oklch(14.5% 0 0deg);
  -webkit-user-select: none;
  user-select: none;

  @media (prefers-color-scheme: dark) {
    background-color: white;
  }
}

.Thumb {
  box-sizing: border-box;
  width: 1rem;
  height: 1rem;
  border: 1px solid oklch(14.5% 0 0deg);
  background-color: white;
  -webkit-user-select: none;
  user-select: none;

  @media (prefers-color-scheme: dark) {
    border: 1px solid white;
    background-color: oklch(14.5% 0 0deg);
  }

  &:has(:focus-visible) {
    outline: 2px solid oklch(14.5% 0 0deg);
    outline-offset: 2px;

    @media (prefers-color-scheme: dark) {
      outline-color: white;
    }
  }
}
```

```tsx
/* docs-comparison.tsx */
import { StencilComparison } from 'docs/src/components/StencilComparison';
import ReactSlider from './react-slider';
import StencilSlider from './stencil-slider';

export default function DocsSliderComparison() {
  return <StencilComparison key="css-modules" component="slider" react={<ReactSlider />} stencil={<StencilSlider />} />;
}
```

```tsx
/* react-slider.tsx */
import { Slider } from '@base-ui/react/slider';
import styles from './index.module.css';

export default function VerticalSlider() {
  return (
    <Slider.Root orientation="vertical" defaultValue={35}>
      <Slider.Control className={styles.Control}>
        <Slider.Track className={styles.Track}>
          <Slider.Indicator className={styles.Indicator} />
          <Slider.Thumb aria-label="Volume" className={styles.Thumb} />
        </Slider.Track>
      </Slider.Control>
    </Slider.Root>
  );
}
```

```tsx
/* stencil-slider.tsx */
export default function StencilSlider() {
  return (
    <fs-slider-root orientation="vertical" default-value={35}>
      <fs-slider-control>
        <fs-slider-track>
          <fs-slider-indicator />
          <fs-slider-thumb aria-label="Volume" />
        </fs-slider-track>
      </fs-slider-control>
    </fs-slider-root>
  );
}
```

### Form integration

To use a slider in a form, pass the slider `name` to `<Slider.Root>`:

```tsx title="Using Slider in a form"
<Form>
  {/* @highlight */}
  <Slider.Root name="volume">
    <Slider.Label>Volume</Slider.Label>
    <Slider.Control>
      <Slider.Track>
        <Slider.Indicator />
        <Slider.Thumb />
      </Slider.Track>
    </Slider.Control>
  </Slider.Root>
</Form>
```

For grouped multi-thumb range sliders in forms, [Fieldset](/react/components/fieldset.md) can provide the shared visible label while each thumb keeps its own `aria-label`:

```tsx title="Using Fieldset with a multi-thumb slider"
<Field.Root>
  {/* @highlight-start */}
  <Fieldset.Root render={<Slider.Root defaultValue={[25, 75]} />}>
    <Fieldset.Legend>Price range</Fieldset.Legend>
    {/* @highlight-end */}
    <Slider.Control>
      <Slider.Track>
        <Slider.Indicator />
        {/* @highlight-start */}
        <Slider.Thumb index={0} aria-label="Minimum price" />
        <Slider.Thumb index={1} aria-label="Maximum price" />
        {/* @highlight-end */}
      </Slider.Track>
    </Slider.Control>
  </Fieldset.Root>
</Field.Root>
```

## API reference

### Root

Groups all parts of the slider.
Renders a `<div>` element.

**Root Props:**

| Prop                   | Type                                                                                      | Default        | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| :--------------------- | :---------------------------------------------------------------------------------------- | :------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| name                   | `string`                                                                                  | -              | Identifies the field when a form is submitted.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| defaultValue           | `number \| number[]`                                                                      | -              | The uncontrolled value of the slider when it's initially rendered. To render a controlled slider, use the `value` prop instead.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| value                  | `number \| number[]`                                                                      | -              | The value of the slider.&#xA;For range sliders, provide an array with one value per thumb.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| onValueChange          | `((value: number \| number[], eventDetails: Slider.Root.ChangeEventDetails) => void)`     | -              | Callback function that is fired when the slider's value changed.&#xA;Receives the new value as the first argument; the originating event is&#xA;available as `eventDetails.event`. The value is also reflected on&#xA;`eventDetails.event.target.value` for form integration. 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 \| number[], eventDetails: Slider.Root.CommitEventDetails) => void)`     | -              | Callback function that is fired when a value change is committed.&#xA;Does not fire if the value did not change, or if the change was canceled.&#xA;**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                                                                       |
| form                   | `string`                                                                                  | -              | Identifies the form that owns the slider inputs.&#xA;Useful when the slider is rendered outside the form.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| locale                 | `Intl.LocalesArgument`                                                                    | -              | The locale used by `Intl.NumberFormat` when formatting the value.&#xA;Defaults to the user's runtime locale.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| thumbAlignment         | `'center' \| 'edge' \| 'edge-client-only'`                                                | `'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 | `'push' \| 'swap' \| 'none'`                                                              | `'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.                                                                                                                                                                                                                                                                                                                 |
| step                   | `number`                                                                                  | `1`            | The granularity with which the slider can step through values. (A "discrete" slider.)&#xA;The `min` prop serves as the origin for the valid values.&#xA;We recommend (max - min) to be evenly divisible by the step.                                                                                                                                                                                                                                                                                                                                                                                                                  |
| largeStep              | `number`                                                                                  | `10`           | The granularity with which the slider can step through values when using Page Up/Page Down or Shift + Arrow Up/Arrow Down.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| minStepsBetweenValues  | `number`                                                                                  | `0`            | The minimum steps between values in a range slider.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| min                    | `number`                                                                                  | `0`            | The minimum allowed value of the slider.&#xA;Should not be equal to max.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| max                    | `number`                                                                                  | `100`          | The maximum allowed value of the slider.&#xA;Should not be equal to min.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| format                 | `Intl.NumberFormatOptions`                                                                | -              | Options to format the value.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| disabled               | `boolean`                                                                                 | `false`        | Whether the slider should ignore user interaction.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| orientation            | `Orientation`                                                                             | `'horizontal'` | The component orientation.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| className              | `string \| ((state: Slider.Root.State) => string \| undefined)`                           | -              | CSS class applied to the element, or a function that&#xA;returns a class based on the component's state.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| style                  | `React.CSSProperties \| ((state: Slider.Root.State) => React.CSSProperties \| undefined)` | -              | Style applied to the element, or a function that&#xA;returns a style object based on the component's state.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| render                 | `ReactElement \| ((props: HTMLProps, state: Slider.Root.State) => ReactElement)`          | -              | Allows you to replace the component's HTML element&#xA;with a different tag, or compose it with another component. Accepts a `ReactElement` or a function that returns the element to render.                                                                                                                                                                                                                                                                                                                                                                                                                                         |

**Root Data Attributes:**

| Attribute        | Type                         | Description                                                                  |
| :--------------- | :--------------------------- | :--------------------------------------------------------------------------- |
| data-dragging    | -                            | Present while the user is dragging.                                          |
| data-orientation | `'horizontal' \| 'vertical'` | Indicates the orientation of the slider.                                     |
| data-disabled    | -                            | Present when the slider is disabled.                                         |
| data-valid       | -                            | Present when the slider is in a valid state (when wrapped in Field.Root).    |
| data-invalid     | -                            | Present when the slider is in an invalid state (when wrapped in Field.Root). |
| data-dirty       | -                            | Present when the slider's value has changed (when wrapped in Field.Root).    |
| data-touched     | -                            | Present when the slider has been touched (when wrapped in Field.Root).       |
| data-focused     | -                            | Present when the slider is focused (when wrapped in Field.Root).             |

### Root.Props

Re-export of [Root](/react/components/slider.md) props.

### Root.State

```typescript
type SliderRootState = {
  /** The index of the active thumb. */
  activeThumbIndex: number;
  /** Whether the component should ignore user interaction. */
  disabled: boolean;
  /** Whether the thumb is currently being dragged. */
  dragging: boolean;
  /** The maximum value. */
  max: number;
  /** The minimum value. */
  min: number;
  /**
   * The minimum steps between values in a range slider.
   * @default 0
   */
  minStepsBetweenValues: number;
  /** The component orientation. */
  orientation: Orientation;
  /**
   * The step increment of the slider when incrementing or decrementing. It will snap
   * to multiples of this value. Decimal values are supported.
   * @default 1
   */
  step: number;
  /** The raw number value of the slider. */
  values: number[];
  /** Whether the field has been touched. */
  touched: boolean;
  /** Whether the field value has changed from its initial value. */
  dirty: boolean;
  /** Whether the field is valid. */
  valid: boolean | null;
  /** Whether the field has a value. */
  filled: boolean;
  /** Whether the field is focused. */
  focused: boolean;
};
```

### Root.ChangeEventReason

```typescript
type SliderRootChangeEventReason = 'input-change' | 'track-press' | 'drag' | 'keyboard' | 'none';
```

### Root.ChangeEventDetails

```typescript
type SliderRootChangeEventDetails = (
  | { reason: 'none'; event: Event }
  | { reason: 'input-change'; event: Event | InputEvent }
  | { reason: 'track-press'; event: PointerEvent | MouseEvent | TouchEvent }
  | { reason: 'drag'; event: PointerEvent | TouchEvent }
  | { reason: 'keyboard'; event: KeyboardEvent }
) & {
  /** Cancels Base UI from handling the event. */
  cancel: () => void;
  /** Allows the event to propagate in cases where Base UI will stop the propagation. */
  allowPropagation: () => void;
  /** Indicates whether the event has been canceled. */
  isCanceled: boolean;
  /** Indicates whether the event is allowed to propagate. */
  isPropagationAllowed: boolean;
  /** The element that triggered the event, if applicable. */
  trigger: Element | undefined;
  /** The index of the active thumb at the time of the change. */
  activeThumbIndex: number;
};
```

### Root.CommitEventReason

```typescript
type SliderRootCommitEventReason = 'input-change' | 'track-press' | 'drag' | 'keyboard' | 'none';
```

### Root.CommitEventDetails

```typescript
type SliderRootCommitEventDetails =
  | { reason: 'none'; event: Event }
  | { reason: 'input-change'; event: Event | InputEvent }
  | { reason: 'track-press'; event: PointerEvent | MouseEvent | TouchEvent }
  | { reason: 'drag'; event: PointerEvent | TouchEvent }
  | { reason: 'keyboard'; event: KeyboardEvent };
```

### Value

Displays the current value of the slider as text.
Renders an `<output>` element.

**Value Props:**

| Prop      | Type                                                                                       | Default | Description                                                                                                                                                                                   |
| :-------- | :----------------------------------------------------------------------------------------- | :------ | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| children  | `((formattedValues: string[], values: number[]) => React.ReactNode) \| null`               | -       | -                                                                                                                                                                                             |
| className | `string \| ((state: Slider.Value.State) => string \| undefined)`                           | -       | CSS class applied to the element, or a function that&#xA;returns a class based on the component's state.                                                                                      |
| style     | `React.CSSProperties \| ((state: Slider.Value.State) => React.CSSProperties \| undefined)` | -       | Style applied to the element, or a function that&#xA;returns a style object based on the component's state.                                                                                   |
| render    | `ReactElement \| ((props: HTMLProps, state: Slider.Value.State) => ReactElement)`          | -       | Allows you to replace the component's HTML element&#xA;with a different tag, or compose it with another component. Accepts a `ReactElement` or a function that returns the element to render. |

**Value Data Attributes:**

| Attribute        | Type                         | Description                                                                  |
| :--------------- | :--------------------------- | :--------------------------------------------------------------------------- |
| data-dragging    | -                            | Present while the user is dragging.                                          |
| data-orientation | `'horizontal' \| 'vertical'` | Indicates the orientation of the slider.                                     |
| data-disabled    | -                            | Present when the slider is disabled.                                         |
| data-valid       | -                            | Present when the slider is in a valid state (when wrapped in Field.Root).    |
| data-invalid     | -                            | Present when the slider is in an invalid state (when wrapped in Field.Root). |
| data-dirty       | -                            | Present when the slider's value has changed (when wrapped in Field.Root).    |
| data-touched     | -                            | Present when the slider has been touched (when wrapped in Field.Root).       |
| data-focused     | -                            | Present when the slider is focused (when wrapped in Field.Root).             |

### Value.Props

Re-export of [Value](/react/components/slider.md) props.

### Value.State

```typescript
type SliderValueState = {
  /** The index of the active thumb. */
  activeThumbIndex: number;
  /** Whether the component should ignore user interaction. */
  disabled: boolean;
  /** Whether the thumb is currently being dragged. */
  dragging: boolean;
  /** The maximum value. */
  max: number;
  /** The minimum value. */
  min: number;
  /**
   * The minimum steps between values in a range slider.
   * @default 0
   */
  minStepsBetweenValues: number;
  /** The component orientation. */
  orientation: Orientation;
  /**
   * The step increment of the slider when incrementing or decrementing. It will snap
   * to multiples of this value. Decimal values are supported.
   * @default 1
   */
  step: number;
  /** The raw number value of the slider. */
  values: number[];
  /** Whether the field has been touched. */
  touched: boolean;
  /** Whether the field value has changed from its initial value. */
  dirty: boolean;
  /** Whether the field is valid. */
  valid: boolean | null;
  /** Whether the field has a value. */
  filled: boolean;
  /** Whether the field is focused. */
  focused: boolean;
};
```

### Indicator

Visualizes the current value of the slider.
Renders a `<div>` element.

**Indicator Props:**

| Prop      | Type                                                                                           | Default | Description                                                                                                                                                                                   |
| :-------- | :--------------------------------------------------------------------------------------------- | :------ | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| className | `string \| ((state: Slider.Indicator.State) => string \| undefined)`                           | -       | CSS class applied to the element, or a function that&#xA;returns a class based on the component's state.                                                                                      |
| style     | `React.CSSProperties \| ((state: Slider.Indicator.State) => React.CSSProperties \| undefined)` | -       | Style applied to the element, or a function that&#xA;returns a style object based on the component's state.                                                                                   |
| render    | `ReactElement \| ((props: HTMLProps, state: Slider.Indicator.State) => ReactElement)`          | -       | Allows you to replace the component's HTML element&#xA;with a different tag, or compose it with another component. Accepts a `ReactElement` or a function that returns the element to render. |

**Indicator Data Attributes:**

| Attribute        | Type                         | Description                                                                  |
| :--------------- | :--------------------------- | :--------------------------------------------------------------------------- |
| data-dragging    | -                            | Present while the user is dragging.                                          |
| data-orientation | `'horizontal' \| 'vertical'` | Indicates the orientation of the slider.                                     |
| data-disabled    | -                            | Present when the slider is disabled.                                         |
| data-valid       | -                            | Present when the slider is in a valid state (when wrapped in Field.Root).    |
| data-invalid     | -                            | Present when the slider is in an invalid state (when wrapped in Field.Root). |
| data-dirty       | -                            | Present when the slider's value has changed (when wrapped in Field.Root).    |
| data-touched     | -                            | Present when the slider has been touched (when wrapped in Field.Root).       |
| data-focused     | -                            | Present when the slider is focused (when wrapped in Field.Root).             |

### Indicator.Props

Re-export of [Indicator](/react/components/slider.md) props.

### Indicator.State

```typescript
type SliderIndicatorState = {
  /** The index of the active thumb. */
  activeThumbIndex: number;
  /** Whether the component should ignore user interaction. */
  disabled: boolean;
  /** Whether the thumb is currently being dragged. */
  dragging: boolean;
  /** The maximum value. */
  max: number;
  /** The minimum value. */
  min: number;
  /**
   * The minimum steps between values in a range slider.
   * @default 0
   */
  minStepsBetweenValues: number;
  /** The component orientation. */
  orientation: Orientation;
  /**
   * The step increment of the slider when incrementing or decrementing. It will snap
   * to multiples of this value. Decimal values are supported.
   * @default 1
   */
  step: number;
  /** The raw number value of the slider. */
  values: number[];
  /** Whether the field has been touched. */
  touched: boolean;
  /** Whether the field value has changed from its initial value. */
  dirty: boolean;
  /** Whether the field is valid. */
  valid: boolean | null;
  /** Whether the field has a value. */
  filled: boolean;
  /** Whether the field is focused. */
  focused: boolean;
};
```

### Track

Contains the slider indicator and represents the entire range of the slider.
Renders a `<div>` element.

**Track Props:**

| Prop      | Type                                                                                       | Default | Description                                                                                                                                                                                   |
| :-------- | :----------------------------------------------------------------------------------------- | :------ | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| className | `string \| ((state: Slider.Track.State) => string \| undefined)`                           | -       | CSS class applied to the element, or a function that&#xA;returns a class based on the component's state.                                                                                      |
| style     | `React.CSSProperties \| ((state: Slider.Track.State) => React.CSSProperties \| undefined)` | -       | Style applied to the element, or a function that&#xA;returns a style object based on the component's state.                                                                                   |
| render    | `ReactElement \| ((props: HTMLProps, state: Slider.Track.State) => ReactElement)`          | -       | Allows you to replace the component's HTML element&#xA;with a different tag, or compose it with another component. Accepts a `ReactElement` or a function that returns the element to render. |

**Track Data Attributes:**

| Attribute        | Type                         | Description                                                                  |
| :--------------- | :--------------------------- | :--------------------------------------------------------------------------- |
| data-dragging    | -                            | Present while the user is dragging.                                          |
| data-orientation | `'horizontal' \| 'vertical'` | Indicates the orientation of the slider.                                     |
| data-disabled    | -                            | Present when the slider is disabled.                                         |
| data-valid       | -                            | Present when the slider is in a valid state (when wrapped in Field.Root).    |
| data-invalid     | -                            | Present when the slider is in an invalid state (when wrapped in Field.Root). |
| data-dirty       | -                            | Present when the slider's value has changed (when wrapped in Field.Root).    |
| data-touched     | -                            | Present when the slider has been touched (when wrapped in Field.Root).       |
| data-focused     | -                            | Present when the slider is focused (when wrapped in Field.Root).             |

### Track.Props

Re-export of [Track](/react/components/slider.md) props.

### Track.State

```typescript
type SliderTrackState = {
  /** The index of the active thumb. */
  activeThumbIndex: number;
  /** Whether the component should ignore user interaction. */
  disabled: boolean;
  /** Whether the thumb is currently being dragged. */
  dragging: boolean;
  /** The maximum value. */
  max: number;
  /** The minimum value. */
  min: number;
  /**
   * The minimum steps between values in a range slider.
   * @default 0
   */
  minStepsBetweenValues: number;
  /** The component orientation. */
  orientation: Orientation;
  /**
   * The step increment of the slider when incrementing or decrementing. It will snap
   * to multiples of this value. Decimal values are supported.
   * @default 1
   */
  step: number;
  /** The raw number value of the slider. */
  values: number[];
  /** Whether the field has been touched. */
  touched: boolean;
  /** Whether the field value has changed from its initial value. */
  dirty: boolean;
  /** Whether the field is valid. */
  valid: boolean | null;
  /** Whether the field has a value. */
  filled: boolean;
  /** Whether the field is focused. */
  focused: boolean;
};
```

### Thumb

The draggable part of the slider at the tip of the indicator.
Renders a `<div>` element and a nested `<input type="range">`.

**Thumb Props:**

| Prop             | Type                                                                                       | Default | Description                                                                                                                                                                                                                                      |
| :--------------- | :----------------------------------------------------------------------------------------- | :------ | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| aria-valuetext   | `string`                                                                                   | -       | A string value forwarded to the [`aria-valuetext`](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Reference/Attributes/aria-valuetext) attribute of the `input`.&#xA;Ignored when `getAriaValueText` is provided.               |
| getAriaLabel     | `((index: number) => string) \| null`                                                      | -       | 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`.                                                        |
| getAriaValueText | `((formattedValue: string, value: number, index: number) => string) \| null`               | -       | A function which returns a string value for the [`aria-valuetext`](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Reference/Attributes/aria-valuetext) attribute of the `input`.&#xA;This is important for screen reader users. |
| index            | `number`                                                                                   | -       | The index of the thumb which corresponds to the index of its value in the&#xA;`value` or `defaultValue` array.&#xA;This prop is required to support server-side rendering for range sliders&#xA;with multiple thumbs.                            |
| onBlur           | `React.FocusEventHandler<HTMLInputElement>`                                                | -       | A blur handler forwarded to the `input`.                                                                                                                                                                                                         |
| onFocus          | `React.FocusEventHandler<HTMLInputElement>`                                                | -       | A focus handler forwarded to the `input`.                                                                                                                                                                                                        |
| onKeyDown        | `React.KeyboardEventHandler<HTMLInputElement>`                                             | -       | A keydown handler forwarded to the `input`.                                                                                                                                                                                                      |
| tabIndex         | `number`                                                                                   | -       | Optional tab index attribute forwarded to the `input`.                                                                                                                                                                                           |
| disabled         | `boolean`                                                                                  | `false` | Whether the thumb should ignore user interaction.                                                                                                                                                                                                |
| inputRef         | `React.Ref<HTMLInputElement>`                                                              | -       | A ref to access the nested input element.                                                                                                                                                                                                        |
| className        | `string \| ((state: Slider.Thumb.State) => string \| undefined)`                           | -       | CSS class applied to the element, or a function that&#xA;returns a class based on the component's state.                                                                                                                                         |
| style            | `React.CSSProperties \| ((state: Slider.Thumb.State) => React.CSSProperties \| undefined)` | -       | Style applied to the element, or a function that&#xA;returns a style object based on the component's state.                                                                                                                                      |
| render           | `ReactElement \| ((props: HTMLProps, state: Slider.Thumb.State) => ReactElement)`          | -       | Allows you to replace the component's HTML element&#xA;with a different tag, or compose it with another component. Accepts a `ReactElement` or a function that returns the element to render.                                                    |

**`index` Prop Example:**

```tsx
<Slider.Root value={[10, 20]}>
  <Slider.Thumb index={0} />
  <Slider.Thumb index={1} />
</Slider.Root>
```

**Thumb Data Attributes:**

| Attribute        | Type                         | Description                                                                  |
| :--------------- | :--------------------------- | :--------------------------------------------------------------------------- |
| data-dragging    | -                            | Present while the user is dragging.                                          |
| data-orientation | `'horizontal' \| 'vertical'` | Indicates the orientation of the slider.                                     |
| data-disabled    | -                            | Present when the slider is disabled.                                         |
| data-valid       | -                            | Present when the slider is in a valid state (when wrapped in Field.Root).    |
| data-invalid     | -                            | Present when the slider is in an invalid state (when wrapped in Field.Root). |
| data-dirty       | -                            | Present when the slider's value has changed (when wrapped in Field.Root).    |
| data-touched     | -                            | Present when the slider has been touched (when wrapped in Field.Root).       |
| data-focused     | -                            | Present when the slider is focused (when wrapped in Field.Root).             |
| data-index       | -                            | Indicates the index of the thumb in range sliders.                           |

### Thumb.Props

Re-export of [Thumb](/react/components/slider.md) props.

### Thumb.State

```typescript
type SliderThumbState = {
  /** The index of the active thumb. */
  activeThumbIndex: number;
  /** Whether the component should ignore user interaction. */
  disabled: boolean;
  /** Whether the thumb is currently being dragged. */
  dragging: boolean;
  /** The maximum value. */
  max: number;
  /** The minimum value. */
  min: number;
  /**
   * The minimum steps between values in a range slider.
   * @default 0
   */
  minStepsBetweenValues: number;
  /** The component orientation. */
  orientation: Orientation;
  /**
   * The step increment of the slider when incrementing or decrementing. It will snap
   * to multiples of this value. Decimal values are supported.
   * @default 1
   */
  step: number;
  /** The raw number value of the slider. */
  values: number[];
  /** Whether the field has been touched. */
  touched: boolean;
  /** Whether the field value has changed from its initial value. */
  dirty: boolean;
  /** Whether the field is valid. */
  valid: boolean | null;
  /** Whether the field has a value. */
  filled: boolean;
  /** Whether the field is focused. */
  focused: boolean;
};
```

### Control

The clickable, interactive part of the slider.
Renders a `<div>` element.

**Control Props:**

| Prop      | Type                                                                                         | Default | Description                                                                                                                                                                                   |
| :-------- | :------------------------------------------------------------------------------------------- | :------ | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| className | `string \| ((state: Slider.Control.State) => string \| undefined)`                           | -       | CSS class applied to the element, or a function that&#xA;returns a class based on the component's state.                                                                                      |
| style     | `React.CSSProperties \| ((state: Slider.Control.State) => React.CSSProperties \| undefined)` | -       | Style applied to the element, or a function that&#xA;returns a style object based on the component's state.                                                                                   |
| render    | `ReactElement \| ((props: HTMLProps, state: Slider.Control.State) => ReactElement)`          | -       | Allows you to replace the component's HTML element&#xA;with a different tag, or compose it with another component. Accepts a `ReactElement` or a function that returns the element to render. |

**Control Data Attributes:**

| Attribute        | Type                         | Description                                                                  |
| :--------------- | :--------------------------- | :--------------------------------------------------------------------------- |
| data-dragging    | -                            | Present while the user is dragging.                                          |
| data-orientation | `'horizontal' \| 'vertical'` | Indicates the orientation of the slider.                                     |
| data-disabled    | -                            | Present when the slider is disabled.                                         |
| data-valid       | -                            | Present when the slider is in a valid state (when wrapped in Field.Root).    |
| data-invalid     | -                            | Present when the slider is in an invalid state (when wrapped in Field.Root). |
| data-dirty       | -                            | Present when the slider's value has changed (when wrapped in Field.Root).    |
| data-touched     | -                            | Present when the slider has been touched (when wrapped in Field.Root).       |
| data-focused     | -                            | Present when the slider is focused (when wrapped in Field.Root).             |

### Control.Props

Re-export of [Control](/react/components/slider.md) props.

### Control.State

```typescript
type SliderControlState = {
  /** The index of the active thumb. */
  activeThumbIndex: number;
  /** Whether the component should ignore user interaction. */
  disabled: boolean;
  /** Whether the thumb is currently being dragged. */
  dragging: boolean;
  /** The maximum value. */
  max: number;
  /** The minimum value. */
  min: number;
  /**
   * The minimum steps between values in a range slider.
   * @default 0
   */
  minStepsBetweenValues: number;
  /** The component orientation. */
  orientation: Orientation;
  /**
   * The step increment of the slider when incrementing or decrementing. It will snap
   * to multiples of this value. Decimal values are supported.
   * @default 1
   */
  step: number;
  /** The raw number value of the slider. */
  values: number[];
  /** Whether the field has been touched. */
  touched: boolean;
  /** Whether the field value has changed from its initial value. */
  dirty: boolean;
  /** Whether the field is valid. */
  valid: boolean | null;
  /** Whether the field has a value. */
  filled: boolean;
  /** Whether the field is focused. */
  focused: boolean;
};
```

### Label

An accessible label that is automatically associated with the slider thumbs.
Renders a `<div>` element.

**Label Props:**

| Prop      | Type                                                                                      | Default | Description                                                                                                                                                                                   |
| :-------- | :---------------------------------------------------------------------------------------- | :------ | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| className | `string \| ((state: Slider.Root.State) => string \| undefined)`                           | -       | CSS class applied to the element, or a function that&#xA;returns a class based on the component's state.                                                                                      |
| style     | `React.CSSProperties \| ((state: Slider.Root.State) => React.CSSProperties \| undefined)` | -       | Style applied to the element, or a function that&#xA;returns a style object based on the component's state.                                                                                   |
| render    | `ReactElement \| ((props: HTMLProps, state: Slider.Root.State) => ReactElement)`          | -       | Allows you to replace the component's HTML element&#xA;with a different tag, or compose it with another component. Accepts a `ReactElement` or a function that returns the element to render. |

### Label.Props

Re-export of [Label](/react/components/slider.md) props.

### Label.State

```typescript
type SliderLabelState = {
  /** The index of the active thumb. */
  activeThumbIndex: number;
  /** Whether the component should ignore user interaction. */
  disabled: boolean;
  /** Whether the thumb is currently being dragged. */
  dragging: boolean;
  /** The maximum value. */
  max: number;
  /** The minimum value. */
  min: number;
  /**
   * The minimum steps between values in a range slider.
   * @default 0
   */
  minStepsBetweenValues: number;
  /** The component orientation. */
  orientation: Orientation;
  /**
   * The step increment of the slider when incrementing or decrementing. It will snap
   * to multiples of this value. Decimal values are supported.
   * @default 1
   */
  step: number;
  /** The raw number value of the slider. */
  values: number[];
  /** Whether the field has been touched. */
  touched: boolean;
  /** Whether the field value has changed from its initial value. */
  dirty: boolean;
  /** Whether the field is valid. */
  valid: boolean | null;
  /** Whether the field has a value. */
  filled: boolean;
  /** Whether the field is focused. */
  focused: boolean;
};
```

## Additional Types

### SliderRootChangeEventCustomProperties

```typescript
type SliderRootChangeEventCustomProperties = {
  /** The index of the active thumb at the time of the change. */
  activeThumbIndex: number;
};
```

### ThumbMetadata

```typescript
type ThumbMetadata = { inputId: string | undefined };
```

## External Types

### Orientation

```typescript
type Orientation = 'horizontal' | 'vertical';
```

## Export Groups

- `Slider.Root`: `Slider.Root`, `Slider.Root.State`, `Slider.Root.Props`, `Slider.Root.ChangeEventReason`, `Slider.Root.ChangeEventDetails`, `Slider.Root.CommitEventReason`, `Slider.Root.CommitEventDetails`
- `Slider.Label`: `Slider.Label`, `Slider.Label.State`, `Slider.Label.Props`
- `Slider.Value`: `Slider.Value`, `Slider.Value.State`, `Slider.Value.Props`
- `Slider.Control`: `Slider.Control`, `Slider.Control.State`, `Slider.Control.Props`
- `Slider.Track`: `Slider.Track`, `Slider.Track.State`, `Slider.Track.Props`
- `Slider.Thumb`: `Slider.Thumb`, `Slider.Thumb.State`, `Slider.Thumb.Props`
- `Slider.Indicator`: `Slider.Indicator`, `Slider.Indicator.State`, `Slider.Indicator.Props`
- `Default`: `SliderRootState`, `SliderRootProps`, `SliderRootChangeEventCustomProperties`, `SliderRootChangeEventReason`, `SliderRootChangeEventDetails`, `SliderRootCommitEventReason`, `SliderRootCommitEventDetails`, `SliderLabelState`, `SliderLabelProps`, `SliderValueState`, `SliderValueProps`, `SliderControlState`, `SliderControlProps`, `SliderTrackState`, `SliderTrackProps`, `ThumbMetadata`, `SliderThumbState`, `SliderThumbProps`, `SliderIndicatorState`, `SliderIndicatorProps`

## Canonical Types

Maps `Canonical`: `Alias` — Use Canonical when its namespace is already imported; otherwise use Alias.

- `Slider.Root.State`: `SliderRootState`
- `Slider.Root.Props`: `SliderRootProps`
- `Slider.Root.ChangeEventReason`: `SliderRootChangeEventReason`
- `Slider.Root.ChangeEventDetails`: `SliderRootChangeEventDetails`
- `Slider.Root.CommitEventReason`: `SliderRootCommitEventReason`
- `Slider.Root.CommitEventDetails`: `SliderRootCommitEventDetails`
- `Slider.Label.State`: `SliderLabelState`
- `Slider.Label.Props`: `SliderLabelProps`
- `Slider.Value.State`: `SliderValueState`
- `Slider.Value.Props`: `SliderValueProps`
- `Slider.Control.State`: `SliderControlState`
- `Slider.Control.Props`: `SliderControlProps`
- `Slider.Track.State`: `SliderTrackState`
- `Slider.Track.Props`: `SliderTrackProps`
- `Slider.Thumb.State`: `SliderThumbState`
- `Slider.Thumb.Props`: `SliderThumbProps`
- `Slider.Indicator.State`: `SliderIndicatorState`
- `Slider.Indicator.Props`: `SliderIndicatorProps`
