Slider
A range input for selecting one value or a range of values.
API Reference
Original primitive API
Behavior, accessibility details, and low-level props are documented by Base UI.
Basic
import { Slider, SliderLabel, SliderValue, SliderThumb,} from "moduix";export function SliderDemo() { return ( <Slider defaultValue={40}> <SliderLabel>Volume</SliderLabel> <SliderValue>{([formattedValue]) => `${formattedValue}%`}</SliderValue> <SliderThumb aria-label="Volume" /> </Slider> );}Full list of component variables available for project-level overrides.
| Property | Default | Description |
|---|---|---|
| --slider-color | var(--color-foreground) | Controls the default slider text color. |
| --slider-control-padding-x | 0.625rem | Controls vertical control horizontal padding. |
| --slider-control-padding-y | 0.625rem | Controls horizontal control vertical padding. |
| --slider-disabled-opacity | var(--opacity-disabled) | Controls disabled slider opacity. |
| --slider-focus-ring-color | var(--color-ring) | Controls thumb focus ring color. |
| --slider-gap | 0.5rem | Controls spacing between slider slots. |
| --slider-height | 12rem | Controls the vertical slider control height. |
| --slider-indicator-bg | var(--color-primary) | Controls filled indicator color. |
| --slider-indicator-radius | inherit | Controls filled indicator corner radius. |
| --slider-label-color | var(--slider-color) | Controls label text color. |
| --slider-label-font-size | var(--text-sm) | Controls label font size. |
| --slider-label-font-weight | var(--weight-regular) | Controls label font weight. |
| --slider-label-line-height | var(--line-height-text-sm) | Controls label line height. |
| --slider-thumb-bg | var(--color-background) | Controls thumb background color. |
| --slider-thumb-border-color | var(--color-border) | Controls thumb border color. |
| --slider-thumb-border-width | var(--border-width-sm) | Controls thumb border width. |
| --slider-thumb-radius | var(--radius-full) | Controls thumb corner radius. |
| --slider-thumb-shadow | var(--shadow-sm) | Controls thumb shadow. |
| --slider-thumb-shadow-dragging | var(--shadow-md) | Controls thumb shadow while dragging. |
| --slider-thumb-size | 1rem | Controls thumb width and height. |
| --slider-track-bg | var(--color-muted) | Controls track background color. |
| --slider-track-border-color | var(--color-border) | Controls track border color. |
| --slider-track-border-width | var(--border-width-sm) | Controls track border width. |
| --slider-track-radius | var(--radius-full) | Controls track corner radius. |
| --slider-track-size | 0.375rem | Controls track thickness. |
| --slider-transition | var(--transition-default) | Controls thumb transition timing. |
| --slider-value-color | var(--slider-color) | Controls value text color. |
| --slider-value-font-size | var(--text-sm) | Controls value font size. |
| --slider-value-font-weight | var(--weight-regular) | Controls value font weight. |
| --slider-value-line-height | var(--line-height-text-sm) | Controls value line height. |
| --slider-width | 12rem | Controls the horizontal slider root width. |
| --slider-width-vertical | fit-content | Controls the vertical slider root width. |
Interactive variables scoped for docs preview without changing size scale tokens.
| Property | Value | Default | Description |
|---|---|---|---|
| --slider-color | var(--color-foreground) | Controls default slider text color. | |
| --slider-focus-ring-color | var(--color-ring) | Controls thumb focus ring color. | |
| --slider-indicator-bg | var(--color-primary) | Controls filled indicator color. | |
| --slider-track-bg | var(--color-muted) | Controls track background color. | |
| --slider-track-border-color | var(--color-border) | Controls track border color. | |
| --slider-track-radius | var(--radius-full) | Controls track corner radius. | |
| --slider-track-size | 0.375rem | Controls track thickness. | |
| --slider-thumb-bg | var(--color-background) | Controls thumb background color. | |
| --slider-thumb-border-color | var(--color-border) | Controls thumb border color. | |
| --slider-thumb-size | 1rem | Controls thumb width and height. |
Anatomy
Slider renders the Base UI control, track, and indicator internally, so consumers only compose the
meaningful content: label, value, and thumbs. Add one SliderThumb for each value in the slider.
Slider
├─ SliderLabel
├─ SliderValue
└─ internal control
└─ internal track
├─ internal indicator
└─ SliderThumb[index]<Slider defaultValue={40}>
<SliderLabel>Volume</SliderLabel>
<SliderValue>{([formattedValue]) => `${formattedValue}%`}</SliderValue>
<SliderThumb aria-label="Volume" />
</Slider>| Part | Role |
|---|---|
Slider | Root state machine. Controls value, range values, steps, orientation, disabled state, and form integration. |
SliderLabel | Visible label connected to the slider inputs. Use it when the control has a readable label on screen. |
SliderValue | Optional formatted value display. It receives formatted values and raw numeric values as render arguments. |
SliderThumb | Interactive handle. Render one thumb for a single value and multiple indexed thumbs for a range. |
The control, track, and indicator are service-like slots for this component. They stay internal by
default and can be styled through classNames.control, classNames.track, and
classNames.indicator when token-level customization is not enough.
Composition
Use Slider for behavior props such as value, defaultValue, onValueChange,
onValueCommitted, min, max, step, largeStep, minStepsBetweenValues, orientation,
thumbAlignment, thumbCollisionBehavior, name, and form.
Use SliderThumb for the accessible name of each handle. A visible SliderLabel labels the group,
but multi-thumb sliders still need distinct aria-label values on each thumb.
Style the root with className, visible parts with their own className, and internally rendered
track structure with classNames:
<Slider
defaultValue={56}
className={styles.slider}
classNames={{
control: styles.control,
track: styles.track,
indicator: styles.indicator,
}}
>
<SliderLabel>Temperature</SliderLabel>
<SliderValue>{([formattedValue]) => `${formattedValue}%`}</SliderValue>
<SliderThumb aria-label="Temperature" className={styles.thumb} />
</Slider>Examples
Range
Pass an array value and render one SliderThumb for each value to let users select a range.
import { Slider, SliderLabel, SliderValue, SliderThumb,} from "moduix";import { useState } from "react";export function RangeSliderDemo() { const [value, setValue] = useState([20, 70] as readonly number[]); return ( <Slider value={value} min={0} max={100} onValueChange={setValue}> <SliderLabel>Price range</SliderLabel> <SliderValue>{([minValue, maxValue]) => `${minValue} - ${maxValue}`}</SliderValue> <SliderThumb index={0} aria-label="Minimum price" /> <SliderThumb index={1} aria-label="Maximum price" /> </Slider> );}Steps and Constraints
Use step, largeStep, and minStepsBetweenValues to make range selection snap to meaningful
increments. thumbCollisionBehavior controls what happens when thumbs meet.
import { Slider, SliderLabel, SliderValue, SliderThumb,} from "moduix";import { useState } from "react";const priceFormatter = new Intl.NumberFormat("en-US", { style: "currency", currency: "USD", maximumFractionDigits: 0,});export function SteppedRangeSliderDemo() { const [value, setValue] = useState([250, 750] as readonly number[]); return ( <Slider value={value} min={0} max={1000} step={50} largeStep={200} minStepsBetweenValues={2} thumbCollisionBehavior="none" format={{ style: "currency", currency: "USD", maximumFractionDigits: 0, }} onValueChange={setValue} > <SliderLabel>Budget</SliderLabel> <SliderValue> {(_, [minValue, maxValue]) => `${priceFormatter.format(minValue)} - ${priceFormatter.format(maxValue)}` } </SliderValue> <SliderThumb index={0} aria-label="Minimum budget" /> <SliderThumb index={1} aria-label="Maximum budget" /> </Slider> );}Controlled
Control the value from React state when the slider needs to synchronize with another control.
import { Slider, SliderLabel, SliderValue, SliderThumb,} from "moduix";import { useState } from "react";import styles from "./slider.module.css";export function ControlledSliderDemo() { const [value, setValue] = useState(24); return ( <div className={styles.stack}> <Slider value={value} onValueChange={setValue}> <SliderLabel>Brightness</SliderLabel> <SliderValue>{([formattedValue]) => `${formattedValue}%`}</SliderValue> <SliderThumb aria-label="Brightness" /> </Slider> <input className={styles.range} type="range" min={0} max={100} value={value} onChange={(event) => { setValue(Number(event.target.value)); }} /> </div> );}.stack { display: grid; gap: var(--spacing-4);}.range { width: 12rem;}Vertical
Set orientation="vertical" and size the vertical track with CSS custom properties.
import { Slider, SliderLabel, SliderValue, SliderThumb,} from "moduix";import styles from "./slider.module.css";export function VerticalSliderDemo() { return ( <div className={styles.verticalContainer}> <Slider orientation="vertical" defaultValue={60} className={styles.verticalSlider}> <SliderLabel>Output</SliderLabel> <SliderValue>{([formattedValue]) => `${formattedValue}%`}</SliderValue> <SliderThumb aria-label="Output" /> </Slider> </div> );}.verticalContainer { display: flex; height: 14rem;}.verticalSlider { --slider-width-vertical: auto; --slider-height: 12rem;}Edge Thumb Alignment
Use thumbAlignment="edge" when the thumb should stay inside the control at the minimum and maximum values.
import { Slider, SliderLabel, SliderValue, SliderThumb,} from "moduix";export function EdgeThumbAlignmentSliderDemo() { return ( <Slider defaultValue={0} thumbAlignment="edge"> <SliderLabel>Zoom</SliderLabel> <SliderValue>{([formattedValue]) => `${formattedValue}%`}</SliderValue> <SliderThumb aria-label="Zoom" /> </Slider> );}Disabled
Use disabled to make the whole slider non-interactive while preserving its current value.
import { Slider, SliderLabel, SliderValue, SliderThumb,} from "moduix";export function DisabledSliderDemo() { return ( <Slider defaultValue={32} disabled> <SliderLabel>Notifications</SliderLabel> <SliderValue>{([formattedValue]) => `${formattedValue}%`}</SliderValue> <SliderThumb aria-label="Notifications" /> </Slider> );}Custom Styles
Use className for the root and classNames for internally rendered slots.
import { Slider, SliderLabel, SliderValue, SliderThumb,} from "moduix";import styles from "./slider.module.css";export function CustomClassesSliderDemo() { return ( <Slider defaultValue={56} classNames={{ control: styles.customControl, track: styles.customTrack, indicator: styles.customIndicator, }} > <SliderLabel>Temperature</SliderLabel> <SliderValue>{([formattedValue]) => `${formattedValue}%`}</SliderValue> <SliderThumb aria-label="Temperature" className={styles.customThumb} /> </Slider> );}.customControl { --slider-control-padding-y: var(--spacing-3);}.customTrack { --slider-track-size: 0.625rem; --slider-track-bg: color-mix(in oklab, var(--color-chart-4) 18%, var(--color-muted)); --slider-track-border-color: transparent;}.customIndicator { --slider-indicator-bg: var(--color-chart-4);}.customThumb { --slider-thumb-size: 1.25rem; --slider-thumb-bg: var(--color-chart-4); --slider-thumb-border-color: var(--color-background);}