Native Solid 2 fork. Original documentation and designs © WorkOS; historical posts retain their original context.

Slider

An input where the user selects a value from within a given range.

Download runnable sandbox
import { Slider } from "@radix-solid/primitives";
import styles from "./styles.module.css";
const SliderDemo = () => <form>
<Slider.Root class={styles.Root} defaultValue={[50]} max={100} step={1}>
<Slider.Track class={styles.Track}>
<Slider.Range class={styles.Range} />
</Slider.Track>
<Slider.Thumb class={styles.Thumb} aria-label="Volume" />
</Slider.Root>
</form>;
export default SliderDemo;

Features

  • Can be controlled or uncontrolled.

  • Supports multiple thumbs.

  • Supports a minimum value between thumbs.

  • Supports touch or click on track to update value.

  • Supports Right to Left direction.

  • Full keyboard navigation.

Anatomy

Import all parts and piece them together.

import { Slider } from "@radix-solid/primitives";
export default () => <Slider.Root>
<Slider.Track>
<Slider.Range />
</Slider.Track>
<Slider.Thumb />
</Slider.Root>;

API Reference

Root

Contains all the parts of a slider. It will render an input for each thumb when used within a form to ensure events propagate correctly.

PropTypeDefault
asChildbooleanfalse
defaultValuenumber[]—
valuenumber[]—
onValueChangefunction—
onValueCommitfunction—
namestring—
disabledbooleanfalse
orientationenum"horizontal"
direnum—
invertedbooleanfalse
minnumber0
maxnumber100
stepnumber1
minStepsBetweenThumbsnumber0
formstring—
Data attributeValues
[data-disabled]

Present when disabled

[data-orientation]"vertical" | "horizontal"

Track

The track that contains the Slider.Range.

PropTypeDefault
asChildbooleanfalse
Data attributeValues
[data-disabled]

Present when disabled

[data-orientation]"vertical" | "horizontal"

Range

The range part. Must live inside Slider.Track.

PropTypeDefault
asChildbooleanfalse
Data attributeValues
[data-disabled]

Present when disabled

[data-orientation]"vertical" | "horizontal"

Thumb

A draggable thumb. You can render multiple thumbs.

PropTypeDefault
asChildbooleanfalse
Data attributeValues
[data-disabled]

Present when disabled

[data-orientation]"vertical" | "horizontal"

Examples

Vertical orientation

Use the orientation prop to create a vertical slider.

// index.tsx
import { Slider } from "@radix-solid/primitives";
import "./styles.css";
export default () => <Slider.Root class="SliderRoot" defaultValue={[50]} orientation="vertical">
<Slider.Track class="SliderTrack">
<Slider.Range class="SliderRange" />
</Slider.Track>
<Slider.Thumb class="SliderThumb" />
</Slider.Root>;
/* styles.css */
.SliderRoot {
position: relative;
display: flex;
align-items: center;
}
.SliderRoot[data-orientation="vertical"] {
flex-direction: column;
width: 20px;
height: 100px;
}
.SliderTrack {
position: relative;
flex-grow: 1;
background-color: grey;
}
.SliderTrack[data-orientation="vertical"] {
width: 3px;
}
.SliderRange {
position: absolute;
background-color: black;
}
.SliderRange[data-orientation="vertical"] {
width: 100%;
}
.SliderThumb {
display: block;
width: 20px;
height: 20px;
background-color: black;
}

Create a range

Add multiple thumbs and values to create a range slider.

import { Slider } from "@radix-solid/primitives";
export default () => <Slider.Root defaultValue={[25, 75]}>
<Slider.Track>
<Slider.Range />
</Slider.Track>
<Slider.Thumb />
<Slider.Thumb />
</Slider.Root>;

Define step size

Use the step prop to increase the stepping interval.

import { Slider } from "@radix-solid/primitives";
export default () => <Slider.Root defaultValue={[50]} step={10}>
<Slider.Track>
<Slider.Range />
</Slider.Track>
<Slider.Thumb />
</Slider.Root>;

Prevent thumb overlap

Use minStepsBetweenThumbs to avoid thumbs with equal values.

import { Slider } from "@radix-solid/primitives";
export default () => <Slider.Root defaultValue={[25, 75]} step={10} minStepsBetweenThumbs={1}>
<Slider.Track>
<Slider.Range />
</Slider.Track>
<Slider.Thumb />
<Slider.Thumb />
</Slider.Root>;

Decoupling the hidden input

By default, Slider.Thumb renders a visually hidden input for form submission. To recompose, move, or exclude that input, you can build each thumb from its lower-level parts instead.

Important: These parts are unstable and prefixed with unstable_, so their API may change in a future release.

  • Slider.unstable_ThumbProvider provides the thumb state and accepts an optional name for the submitted value.
  • Slider.unstable_ThumbTrigger is the draggable thumb element.
  • Slider.unstable_BubbleInput is the visually hidden input that Slider.Thumb renders by default. Omit it when you don't need form submission.
import { Slider } from "@radix-solid/primitives";
export default () => <Slider.Root defaultValue={[25, 75]}>
<Slider.Track>
<Slider.Range />
</Slider.Track>
<Slider.unstable_ThumbProvider name="price[min]">
<Slider.unstable_ThumbTrigger />
<Slider.unstable_BubbleInput />
</Slider.unstable_ThumbProvider>
<Slider.unstable_ThumbProvider name="price[max]">
<Slider.unstable_ThumbTrigger />
<Slider.unstable_BubbleInput />
</Slider.unstable_ThumbProvider>
</Slider.Root>;

Accessibility

Adheres to the Slider WAI-ARIA design pattern.

Keyboard Interactions

KeyDescription
ArrowRight
Increments/decrements by the step value depending on orientation.
ArrowLeft
Increments/decrements by the step value depending on orientation.
ArrowUp
Increases the value by the step amount.
ArrowDown
Decreases the value by the step amount.
PageUp
Increases the value by a larger step.
PageDown
Decreases the value by a larger step.
Shift + ArrowUp
Increases the value by a larger step.
Shift + ArrowDown
Decreases the value by a larger step.
Home
Sets the value to its minimum.
End
Sets the value to its maximum.

Custom APIs

Create your own API by abstracting the primitive parts into your own component.

Abstract all parts

This example abstracts all of the Slider parts so it can be used as a self closing element.

Usage

import { Slider } from "./your-slider";
export default () => <Slider defaultValue={[25]} />;

Implementation

import { type ComponentProps } from "solid-js";
// your-slider.tsx
import { Slider as SliderPrimitive } from "@radix-solid/primitives";
export const Slider = (p: Extract<ComponentProps<typeof SliderPrimitive.Root>, {
asChild?: false;
}>) => {
const value = () => p.value ?? p.defaultValue ?? [0];
return <SliderPrimitive.Root {...p} ref={p.ref}>
<SliderPrimitive.Track>
<SliderPrimitive.Range />
</SliderPrimitive.Track>
{value().map(() => <SliderPrimitive.Thumb />)}
</SliderPrimitive.Root>;
};

Caveats

Mouse events are not fired

Because of a limitation we faced during implementation, the following example won't work as expected and the onMouseDown and onMouseUp event handlers won't be fired:

<Slider.Root onMouseDown={() => console.log("onMouseDown")} onMouseUp={() => console.log("onMouseUp")}>
…
</Slider.Root>

We recommend using pointer events instead (eg. onPointerDown, onPointerUp). Regardless of the above limitation, these events are better suited for cross-platform/device handling as they are fired for all pointer input types (mouse, touch, pen, etc.).