Thumbprint logo

Components

Slider

Control for choosing a value along a continuous or stepped interval.

Slider is built on React Aria and styled with Thumbprint v2 semantic tokens, so it re-themes automatically in dark mode. Use it when the relative position within a range matters more than typing an exact number — think price ranges, distance, or volume. When users need to enter a precise value, prefer a text or number input.

Keyboard support comes from React Aria: arrow keys adjust the value by step, Home/End jump to the bounds, and Page Up/Down move in larger increments. The track and thumb accept clicks and drags anywhere within a 44px-tall touch target.

Basic slider

Provide value and onChange for a controlled slider. In single-thumb mode onChange receives a number. Every slider needs a visible label or, failing that, an accessibilityLabel.

function SliderExample() {
    const [value, setValue] = React.useState(40);

    return <Slider label="Volume" value={value} onChange={setValue} />;
}

Uncontrolled sliders

For an uncontrolled slider, set an initial value with defaultValue and let React Aria manage the state internally. Use onChangeEnd to read the final value once the user releases the thumb.

<Slider label="Volume" defaultValue={40} onChangeEnd={(value) => console.log(value)} />

Showing the current value

Set shouldShowValue to display the current value across from the label. Showing the value is recommended so users know exactly what they have selected — the slider’s fill alone should not be the only indicator.

<Slider label="Volume" defaultValue={40} shouldShowValue />

Steps and bounds

min, max, and step control the interval. Use stepped increments when only certain values are valid; the thumb snaps to each step. Consider rendering the minimum and maximum below the slider so users understand the full scale.

function SliderExample() {
    const [value, setValue] = React.useState(100);

    return (
        <div>
            <Slider
                label="Search radius"
                value={value}
                onChange={setValue}
                min={0}
                max={500}
                step={25}
                shouldShowValue
            />
            <div className="flex justify-between black-300 tp-body-3">
                <span>0 miles</span>
                <span>500 miles</span>
            </div>
        </div>
    );
}

Formatting values

formatOptions accepts Intl.NumberFormat options and formats both the visible value and each thumb’s aria-valuetext, so assistive technologies announce the formatted value too.

<Slider
    label="Budget"
    defaultValue={75}
    min={0}
    max={200}
    shouldShowValue
    formatOptions={{ style: 'currency', currency: 'USD', maximumFractionDigits: 0 }}
/>

Range slider

Pass an array of two numbers to select a range with two thumbs — useful for filtering by a minimum and maximum. onChange then receives [start, end], the fill runs between the thumbs, and React Aria prevents the thumbs from crossing. Always provide thumbAccessibilityLabels in range mode so assistive technologies can tell the thumbs apart.

function SliderExample() {
    const [value, setValue] = React.useState([25, 75]);

    return (
        <Slider
            label="Price range"
            value={value}
            onChange={setValue}
            shouldShowValue
            formatOptions={{ style: 'currency', currency: 'USD', maximumFractionDigits: 0 }}
            thumbAccessibilityLabels={['Minimum price', 'Maximum price']}
        />
    );
}

When one handler serves both modes, narrow the value first: Array.isArray(value) distinguishes a range from a single number.

Disabled sliders

The isDisabled prop visually and functionally disables the slider along with its label and value display.

<div>
    <Slider label="Volume" defaultValue={40} shouldShowValue isDisabled />
    <div className="mt4">
        <Slider
            label="Price range"
            defaultValue={[25, 75]}
            shouldShowValue
            thumbAccessibilityLabels={['Minimum price', 'Maximum price']}
            isDisabled
        />
    </div>
</div>

Accessibility and usage notes

The interactive track is 44px tall even though the visible rail is 8px, giving a comfortable touch target without extra work. Prefer onChangeEnd over onChange for expensive work like network requests — onChange fires on every step while dragging. For tasks that require precision, pair the slider with a text input so users can type an exact value.

The full list of props is in the table below.

Props

Slider

  • label

    Visible label rendered above the slider and associated with it for assistive technologies. If omitted, the developer must use the accessibilityLabel prop to label the slider.

    Type
    string
  • value

    The current value for a controlled slider. Pass a single number for one thumb, or an array of two numbers ([start, end]) for a range slider. Maps to React Aria's value.

    Type
    number | number[]
  • defaultValue

    The initial value for an uncontrolled slider. Pass a single number for one thumb, or an array of two numbers for a range slider. Maps to React Aria's defaultValue.

    Type
    number | number[]
  • onChange

    Function that runs as the value changes while dragging or stepping with the keyboard. It receives a number in single mode and an array of two numbers in range mode.

    Type
    (value: number | number[]) => void
  • onChangeEnd

    Function that runs once interaction ends (pointer or key released). Useful for committing the value (e.g. firing a network request) without reacting to every step. Maps to React Aria's onChangeEnd.

    Type
    (value: number | number[]) => void
  • min

    The minimum allowed value. Maps to React Aria's minValue.

    Type
    number
    Default
    0
  • max

    The maximum allowed value. Maps to React Aria's maxValue.

    Type
    number
    Default
    100
  • step

    The granularity the value snaps to. Maps to React Aria's step.

    Type
    number
    Default
    1
  • shouldShowValue

    Shows the current value (or start – end in range mode) across from the label, formatted with formatOptions.

    Type
    boolean
    Default
    false
  • formatOptions

    Intl.NumberFormat options used to format the displayed value and each thumb's aria-valuetext — e.g. { style: 'currency', currency: 'USD' }. Maps to React Aria's formatOptions.

    Type
    Intl.NumberFormatOptions
  • isDisabled

    Disables the slider and its label.

    Type
    boolean
    Default
    false
  • accessibilityLabel

    Accessible label for the slider when no visible label is provided. Maps to React Aria's aria-label.

    Type
    string
  • thumbAccessibilityLabels

    Accessible labels for the individual thumbs, in value order (e.g. ['Minimum', 'Maximum']). Required in range mode so assistive technologies can distinguish the thumbs; unnecessary in single mode.

    Type
    string[]
  • id

    The id added to the slider's root element as an HTML attribute.

    Type
    string
  • dataTestId

    A selector hook into the React component for use in automated testing environments. Applied to the root element.

    Type
    string