Slider
A value chosen along a line.
Overview
A value chosen along a line.
First example
<Slider defaultValue={40} onValueCommit={save}><Slider.Output /><Slider.Track><Slider.Fill /><Slider.Thumb /></Slider.Track></Slider>
Anatomy
<Slider>
<Slider.Output />
<Slider.Track>
<Slider.Fill />
<Slider.Thumb />
</Slider.Track>
</Slider>
Slider— the value, the range, and the styles the slots read.Slider.Output— the value in words. Optional.Slider.Track— the line, and the only node that knows how long it is.Slider.Fill— the part behind the thumb.Slider.Thumb— what the finger holds.
Usage
Basic
<Slider defaultValue={40} onValueCommit={save}>
<Slider.Output />
<Slider.Track>
<Slider.Fill />
<Slider.Thumb />
</Slider.Track>
</Slider>
Two callbacks, and the difference matters
onValueChange fires on every step the thumb crosses, including mid-drag. It is what a
live preview reads.
onValueCommit fires once, when the finger lifts. It is where a network call belongs,
because the first one can fire fifty times in a second.
Steps
<Slider min={5} max={95} step={10} />
Eleven stops at 5, 15, 25 … The snap counts steps from the minimum rather than rounding
the value, so that range stops where it says it does and not at 10, 20, 30. step={0} is
continuous.
Formatting the output
<Slider.Output>{value => `${value} %`}</Slider.Output>
children may be a function of the value. A format prop would have been the same thing
with less room in it.
Style as props
<Slider.Track height={8} />
<Slider.Thumb width={32} />
Full RN names, full RN values (R14). Every node takes them.
Root props
SliderProps
The node's inherited React Native props apply too, and so do its style props — padding, margin, width and the rest.
| Prop | Type | Required | Description |
|---|---|---|---|
| children | ReactNode | No | — |
| size | SliderSize | undefined | No | — |
| orientation | SliderOrientation | undefined | No | — |
| radius | RadiusKey | undefined | No | — |
| color | string | undefined | No | The tint (R7) — a raw value, never a token. Paints the fill and the thumb. |
| value | SliderValue | undefined | No | A number for one thumb, a pair for a range. The shape decides how many thumbs there are, and it comes back out the same way — a slider given `[20, 60]` reports `[20, 60]`, never `20`. |
| defaultValue | SliderValue | undefined | No | — |
| onValueChange | ((value: SliderValue) => void) | undefined | No | Fires on every step a thumb crosses, including while it is being dragged. |
| onValueCommit | ((value: SliderValue) => void) | undefined | No | Fires once, when the finger lifts. What a network call belongs on. |
| min | number | undefined | No | — |
| max | number | undefined | No | — |
| step | number | undefined | No | Set it to `0` for a continuous slider. |
| isDisabled | boolean | undefined | No | — |
Slots
SliderFillProps
The node's inherited React Native props apply too, and so do its style props — padding, margin, width and the rest.
SliderOutputProps
The node's inherited React Native props apply too, and so do its style props — padding, margin, width and the rest.
| Prop | Type | Required | Description |
|---|---|---|---|
| children | ReactNode | ((value: SliderValue) => ReactNode) | No | Given the current value, so the caller can format it. Defaults to the number, or to the two ends joined by an en dash when the slider is a range. |
SliderThumbProps
The node's inherited React Native props apply too, and so do its style props — padding, margin, width and the rest.
| Prop | Type | Required | Description |
|---|---|---|---|
| index | number | undefined | No | Which thumb this is. `0` on a plain slider, `0` and `1` on a range — written out rather than conjured by the track, so a range is two slots you can see and style apart rather than one that silently became two. |
| accessibilityValueText | ((value: number) => string) | undefined | No | What a screen reader reads instead of the raw number. |
SliderTrackProps
The node's inherited React Native props apply too, and so do its style props — padding, margin, width and the rest.
| Prop | Type | Required | Description |
|---|---|---|---|
| children | ReactNode | No | — |
Variants, sizes and colour
Accessibility
The thumb is adjustable, carrying min, max and now, and it answers the platform's
increment and decrement actions by one step — without that the platform guesses one
percent of the range, which on a slider of five stops moves nothing.
Migration from legacy
| Legacy | v1 |
|---|---|
value / onValueChange | unchanged |
onSlidingComplete | onValueCommit |
minimumValue | min |
maximumValue | max |
themeColor="primary" | color={theme.colors.accent} |
customAppearance={{ … }} | style on the slot that key named |
Implementation notes
How it is put together
The travel is inset by half a thumb at each end. Otherwise the thumb hangs over the track's ends at the minimum and the maximum, and the fill runs out from under it. The fill runs to the thumb's centre rather than to the raw proportion, for the same reason.
A press anywhere on the track moves the thumb there. It is the half of a slider people forget: dragging a narrow thumb is a fine gesture on a mouse and a poor one on a finger.
The thumb grows 15% under the press rather than moving. The finger is already covering it, so the scale is what you see in the gap around it — and it is the only confirmation a slider can give that the drag has started. Stiff and well damped: a confirmation should arrive, not wobble.
The value crosses to the JS thread and the scale does not. The pan computes the new
position on the UI thread and hands the value back over runOnJS, which is the one hop
that has to happen — the value is React state. The scale stays where it is.
Not here yet
A range slider, with two thumbs. The context already carries what a second thumb would
need, and useSlider is exported for anyone who wants to write one — but two thumbs is two
values, a different type for value, and rules about which one gives way. Worth its own
change.
A vertical slider. The same arithmetic on the other axis, but also a different gesture and a different layout.