Persona

Slider

Inputs · 20 props · Updated Sep 22, 2026

A slider sets a number by dragging. Pass one number and you get one thumb; pass two in an array and the same component renders a range. It is built on react-aria’s slider, which is where the keyboard, the value announcements and the number formatting come from.

  • 0
    100
    0
    100
    Minimum label (optional) the bottom of the range, from minLabel. Drawn only with showLabels.
  • 0
    100
    0
    100
    Track the rail the thumb travels. The filled part is not a separate element; the rail is a gradient with a color stop at the current value, and track={false} flattens it.
  • 0
    100
    0
    100
    Thumb the handle, and the only part that moves. Its position is the value; the tooltip that names the number appears while the thumb is focused or held.
  • 0
    100
    0
    100
    Maximum label (optional) the top of the range, from maxLabel.

A slider cannot be typed into, read at rest, or copied out of. What it can do is change the value while the reader drags it, so they can stop when the result looks right and never find out what “68” meant. That trade is the only reason to reach for one.

Where the number itself is the answer, a text input wins on all three counts a slider loses. A Select or Radio Buttons beat it for a small set of discrete values, which a slider makes fiddly to hit. And a value nobody can change should not be in one at all: a thumb on a track is an invitation to drag it.

value and defaultValue take a number or an array of numbers, and the length of the array is the number of thumbs. onChange hands back the shape you passed in, so a single-value slider gets a number rather than an array of one.

The value is only on screen while the thumb is held

Section titled “The value is only on screen while the thumb is held”

The tooltip above the thumb is the only readout, and it is there while the thumb has focus or is being pressed, closing about half a second after the reader lets go. hideTooltips removes it entirely, and nothing renders the value at rest.

So if the number has to stay on screen, put it there yourself, beside the slider. A reader comparing a threshold against a figure elsewhere on the page cannot hold a value that vanishes when they look away.

Format the number once, with formatOptions

Section titled “Format the number once, with formatOptions”

formatOptions takes Intl.NumberFormat options, and the string it produces is both the tooltip’s text and the aria-valuetext a screen reader reads out. A currency or a unit set here is announced as well as shown, where the same formatting done by hand in a label leaves the announcement as a bare number.

step sets which values the reader can reach, and it defaults to 1 on a range of 0 to 100. On the default 300px track that puts the hundred reachable values three pixels apart, which a drag can hit.

Widen the range without widening the step and that stops being true. Zero to a thousand in steps of one puts more than three values in every pixel, so the thumb cannot be landed on a number the reader picked. Pick the step the drag can hit, and let the range follow.

Draw the endpoints, or the range is a guess

Section titled “Draw the endpoints, or the range is a guess”

showLabels renders minLabel and maxLabel, which fall back to min and max. Both take any node, so the unit belongs here. Without showLabels neither renders, and a bare track with no tooltip showing says nothing at all about what it spans.

Fill the track unless the value has no low-to-high meaning

Section titled “Fill the track unless the value has no low-to-high meaning”

The rail paints the part below the value in the accent color, as a gradient stop rather than a second element. It is the only thing that reports the value when the tooltip is closed, which is most of the time. track={false} replaces it with a plain rail, and is for the case where the value has no low-to-high meaning to fill toward.

width defaults to 300px. Pass auto and the slider takes the width of its container, which is what a slider in a form wants.

A slider’s visible label is not its accessible name

Section titled “A slider’s visible label is not its accessible name”

A slider’s accessible name comes from aria-label or aria-labelledby and nowhere else. The visible label above it belongs to FormField, and Slider does not read FormField’s context, so that label is not yet the slider’s name. Give FormField an inputId and hand the slider an aria-labelledby of the same id with -label appended.

Nothing in the API names a thumb. Both thumbs of a range slider take the slider’s own name, so a screen reader announces the same label twice and distinguishes the two only by their values. There is no prop to fix it, and “Minimum price” and “Maximum price” cannot currently be reached from this component.

Each thumb is a visually hidden range input, which is where arrow keys, Home and End come from, and what makes the value announceable at all.

The label names what changes, formatOptions carries the unit into both the tooltip and the announcement, and minLabel and maxLabel carry the bounds. A label reading “Opacity” above a tooltip reading “34%” tells the reader more than “Opacity (%)” above a bare “34”.

A slider clamps to its own range, so it cannot produce a value that is out of bounds or the wrong type. An error under one is always about the consequence of a legal choice, which means it has something to say: not “enter a valid number”, but what a threshold this low will do.

NameType
min

number

minLabel

ReactNode

max

number

maxLabel

ReactNode

onChange

((value: T) => void)

value

T

defaultValue

T

step

number

showLabels

boolean

Show labels on ends of track

track

boolean

Track style

hideTooltips

boolean

Hide tooltips on slider thumbs

width

number, auto

disabled

boolean

formatOptions

NumberFormatOptions

id

string

className

string

name

string

onBlur

FocusEventHandler<HTMLDivElement>

aria-label

string

aria-labelledby

string

Was this page helpful?