Slider

stable
Since 1.1
Range input with one or two thumbs, supporting drag, keyboard, and assistive-technology adjustment with step snapping and value announcement.
Forms
primitive
Form Control
Needs State Matrix
import { Slider } from '@ivim/native/components';

When to use

Use when
Someone is choosing a value from a continuous or evenly stepped range and the approximate position matters more than the exact number.
You need a two-ended range filter, such as a price or date window.
Don't use when
The exact value matters and is hard to hit by dragging — use a numeric Input, optionally paired with a slider.
There are only a few discrete options — use SegmentedControl or RadioGroup so every choice is directly selectable.
You are showing progress rather than collecting input — use Progress, which is display-only by design.

Playground

Adjust the controls to preview live prop combinations. The code snippet updates to match the current selection.
Volume
40
40
size
size
Label placement
labelPlacement
Disabled
isDisabled
Read only
isReadOnly
Label
label
<Slider labelPlacement="bottom" label="Volume" />

Example

State Matrix
Default (uncontrolled)
Controlled, with live read-out
Brightness
60
60
Range
Price range
25 – 75
25 – 75
Stepped (step=10)
Servings
30
30
Custom range and formatting
Temperature
22°C
22°C
Label placement: endpoints
Volume
0
100
Label placement: floating
55
Small
Large
Read only
Read only
64
64
Disabled
Disabled
64
64
Platform adaptations
Untitled UI's web slider is a mouse-and-keyboard control. This implementation keeps the same user job but drives it with PanResponder so one code path serves touch and mouse, and adds increment/decrement accessibility actions so VoiceOver and TalkBack can adjust the value — behavior the web reference has no equivalent for.

Anatomy

The parts that compose this component.
1
Track
Full-width rail representing the range from `minValue` to `maxValue`. Owns the drag gesture, and is itself the adjustable element in single-value mode.
2
Fill
Portion of the track covered by the value. For a range it spans between the two thumbs. Pointer-transparent so drags stay track-relative.
3
Thumb
Draggable handle. One in single-value mode; two in range mode, where each is separately focusable and announced.
4
Label
Optional value read-out positioned by `labelPlacement` — beside the label, at the track endpoints, below the track, or floating above the thumb.

Guidelines

Do
Show the current value with `labelPlacement`, so the selection is readable without interpreting the thumb position.
Do
Set `step` to the smallest increment that is actually meaningful — it makes both dragging and keyboard adjustment land on useful values.
Do
Use `onChangeEnd` for expensive commits (network calls, recomputation) and `onChange` only for live preview.
Don't
Use a slider for precise or wide-ranging numeric entry — dragging cannot reliably hit one value in a range of thousands.
Don't
Rely on the fill color alone to convey the value; pair it with a visible label or an accessible name that describes the units.

Props

Public props for this component. Required props are marked; defaults reflect the component implementation.
value
number | [number, number]
Controlled value. A tuple makes this a two-thumb range slider.
defaultValue
number | [number, number]
Uncontrolled initial value. A tuple makes this a two-thumb range slider.
onChange
(value: number | [number, number]) => void
Fires on every committed change during a drag, key press, or assistive-technology adjustment.
onChangeEnd
(value: number | [number, number]) => void
Fires once when a drag gesture releases. Use for expensive commits.
minValue
number
default: 0
Lower bound of the range.
maxValue
number
default: 100
Upper bound of the range.
step
number
default: 1
Increment values snap to, counted from minValue. A non-positive step disables snapping.
isDisabled
boolean
default: false
Dims the control, rejects input, and announces as disabled.
isReadOnly
boolean
default: false
Rejects input but still renders and announces as an enabled control.
label
ReactNode
Visible label; also the accessible name when aria-label is absent.
aria-label
string
Accessible name when there is no visible label.
labelPlacement
'none' | 'endpoints' | 'bottom' | 'floating'
default: 'none'
Where the value read-out sits relative to the track.
formatValue
(value: number) => string
Formats the value for display and for the announced accessibilityValue.text.
size
'sm' | 'md' | 'lg'
default: 'md'
Controls track thickness and thumb diameter.
trackContent
ReactNode
Custom content filling the track — a gradient for a hue or brightness picker — replacing the default progress fill. Rendered pointer-transparent so drag coordinates stay track-relative.

Deviations from Untitled UI

Where this component deliberately differs from Untitled UI's API, and why. These are kept choices, not gaps to close.
Untitled UI
`labelPosition` / `labelFormatter` / `valueFormatter`
Ours
`labelPlacement` / `formatValue`
Kept: an internally consistent pair shared by Slider, Progress, and ProgressCircle. A cross-library rename would churn three APIs for cosmetic parity.

Accessibility

Roles and screen-reader behavior this component provides, plus keyboard interactions.
Sets accessibilityRole="adjustable" and accessible on the adjustable element — without accessible, iOS does not expose the adjustable trait at all.
Publishes accessibilityValue with min, max, and now; formatValue additionally supplies text so units are announced ("20°C" rather than "20").
Declares increment and decrement accessibilityActions, which is what VoiceOver swipe-up/down and TalkBack adjustment gestures invoke.
In range mode each thumb is a separate adjustable element, so both ends can be reached and announced independently.
Disabled is announced through accessibilityState; read-only rejects input while still reporting as an enabled control.
Tab
Moves focus to the slider (web).
Arrow Right / Arrow Up
Increases the value by one step.
Arrow Left / Arrow Down
Decreases the value by one step.
Page Up / Page Down
Jumps by a tenth of the range, or one step if that is larger.
Home / End
Jumps to the minimum or maximum.

Platform & RTL

Behavior that differs across the platforms this component runs on.
Web
Focusable with a visible focus ring; the full WAI-ARIA slider key set is handled and arrow/page keys are prevented from scrolling the page.
iOS
Drag via PanResponder. VoiceOver announces the value and adjusts it with swipe up/down through the increment/decrement actions.
Android
Drag via PanResponder. TalkBack adjustment gestures map onto the same increment/decrement actions.
RTL
The track is laid out with logical direction; values still run from minValue at the start edge to maxValue at the end edge.

State coverage

Interaction and visual states this component supports.
default
focus
error
disabled
selected

Token references

Semantic design tokens this component page exercises. Tap one to edit it live.