Slider
Free · MITReact Native · ExpoSingle and range sliders whose thumbs follow the finger 1:1 and settle onto the nearest step on release, with a value bubble that grows out of the thumb while dragging and optional step ticks that tick.
Installation
$ npx shadcn@latest add https://goodui.dev/native/r/slider.jsonThen run npx expo install --fix so react-native-gesture-handler, react-native-reanimated match your Expo SDK. Files land in components/goodui-native/slider.
- Wrap the app in GestureHandlerRootView and ThemeProvider.
Usage
import { useState } from "react";
import { RangeSlider, Slider } from "@/components/goodui-native/slider/slider";
export function Filters() {
const [distance, setDistance] = useState(10);
const [price, setPrice] = useState<[number, number]>([40, 180]);
return (
<>
<Slider accessibilityLabel="Distance" value={distance} onValueChange={setDistance} min={1} max={50} formatValue={(v) => `${v} km`} />
<RangeSlider
accessibilityLabel="Price"
value={price}
onValueChange={setPrice}
onSlidingComplete={(range) => refetch(range)}
min={0}
max={300}
step={10}
formatValue={(v) => `$${v}`}
/>
</>
);
}When to use
- Picking a value where the position matters more than the exact digit: volume, brightness, budget, distance.
- A range: price filter, age range, time window (RangeSlider).
- A small set of evenly spaced values with feedback: rating 1 to 5, tip percentage (step with showTicks).
- An exact number the person types: use text-field.
- Small counts changed by one (guests, quantity): use quantity-stepper.
- Two to five named options: use segmented-control.
Examples
Stepped with ticks and an always-visible value
<Slider accessibilityLabel="Tip" defaultValue={15} min={0} max={30} step={5} showTicks showValue="always" formatValue={(v) => `${v}%`} />Continuous, small, status tone
<Slider size="sm" tone="warning" step={0} showValue="never" accessibilityLabel="Brightness" />API reference
Slider
| Prop | Type | Default |
|---|---|---|
| min Lowest value. Default 0. | number | — |
| max Highest value. Default 100. | number | — |
| step Values snap to multiples of this. Default 1. `0` is continuous. | number | — |
| showTicks Dots at every step, and a select haptic each time the value crosses one. Shown only when there are 40 steps or fewer. | boolean | — |
| showValue Value bubble above the thumb: `drag` appears while dragging, `always` stays and grows while dragging, `never`. | "drag" | "always" | "never" | — |
| formatValue Text for a value in the bubble and for screen readers, for example `(v) => \`$${v}\``. | (value: number) => string | — |
| tone Fill color. `accent` by default; status tones only when the value means a status. | "success" | "warning" | "danger" | "accent" | — |
| size Thumb 22 (`sm`) or 28 pt (`md`). The touch area stays at least 44 pt tall. | "sm" | "md" | — |
| disabled Dims the control and ignores presses. | boolean | — |
| haptic `false` silences the tick and edge haptics. | boolean | — |
| onSlidingStart Called when a drag or tap starts changing the value. | () => void | — |
| accessibilityLabel Screen reader label, for example "Volume". | string | — |
| labels Overrides for the built-in strings; a GooduiLocaleProvider pack sets them app-wide. | Partial<SliderLabels> | — |
| style Style for the outer container. | StyleProp<ViewStyle> | — |
| testID Identifier for end-to-end tests. | string | — |
| value The value (controlled). Pair it with `onValueChange`. | number | — |
| defaultValue Initial value when uncontrolled. Defaults to `min`. | number | — |
| onValueChange Called while dragging, each time the snapped value changes. | (value: number) => void | — |
| onSlidingComplete Called once when the finger lifts, with the final value. Save or fetch here. | (value: number) => void | — |
RangeSlider
| Prop | Type | Default |
|---|---|---|
| min Lowest value. Default 0. | number | — |
| max Highest value. Default 100. | number | — |
| step Values snap to multiples of this. Default 1. `0` is continuous. | number | — |
| showTicks Dots at every step, and a select haptic each time the value crosses one. Shown only when there are 40 steps or fewer. | boolean | — |
| showValue Value bubble above the thumb: `drag` appears while dragging, `always` stays and grows while dragging, `never`. | "drag" | "always" | "never" | — |
| formatValue Text for a value in the bubble and for screen readers, for example `(v) => \`$${v}\``. | (value: number) => string | — |
| tone Fill color. `accent` by default; status tones only when the value means a status. | "success" | "warning" | "danger" | "accent" | — |
| size Thumb 22 (`sm`) or 28 pt (`md`). The touch area stays at least 44 pt tall. | "sm" | "md" | — |
| disabled Dims the control and ignores presses. | boolean | — |
| haptic `false` silences the tick and edge haptics. | boolean | — |
| onSlidingStart Called when a drag or tap starts changing the value. | () => void | — |
| accessibilityLabel Screen reader label, for example "Volume". | string | — |
| labels Overrides for the built-in strings; a GooduiLocaleProvider pack sets them app-wide. | Partial<SliderLabels> | — |
| style Style for the outer container. | StyleProp<ViewStyle> | — |
| testID Identifier for end-to-end tests. | string | — |
| value The low and high values (controlled). | [number, number] | — |
| defaultValue Initial values when uncontrolled. Defaults to `[min, max]`. | [number, number] | — |
| onValueChange Called while dragging, each time either snapped value changes. | (value: [number, number]) => void | — |
| onSlidingComplete Called once when the finger lifts, with the final pair. | (value: [number, number]) => void | — |
| minDistance Smallest gap between the two values. Default one step. | number | — |
| thumbLabels Screen reader labels of the two thumbs. Same as `labels.minimum` and `labels.maximum`. | [string, string] | — |
Motion and haptics
- Dragging: the thumb tracks the finger 1:1 (grabbing it keeps the finger's offset, grabbing the track brings the nearest thumb to the finger) and scales to 1.08.
- Release: the thumb settles onto the step the value already shows on the snappy spring.
- Tapping the track moves the nearest thumb there on the smooth spring.
- The value bubble grows out of the top of the thumb while dragging (showValue 'drag' appears from nothing, 'always' grows from 84 %).
- Outside value changes move the thumbs on the smooth spring.
- Reduced motion: no thumb or bubble scaling (the bubble simply appears), release and outside changes jump to the value; dragging still follows the finger.
- Haptic: select each time the value crosses a tick (with showTicks)
- Haptic: select when the value reaches min or max
- The gesture and all thumb, fill and bubble motion run on the UI thread.
- React updates only when the snapped value changes, not per frame. Use onSlidingComplete for expensive work.
Accessibility
- Each thumb is an adjustable element (a slider on the web) with min, max, now and the formatted text as its value.
- Screen readers use the increment and decrement actions; one action moves one step (or 5 % of the range when continuous).
- Range thumbs are labelled '<label>, Minimum' and '<label>, Maximum' (thumbLabels to localize).
- On the web each thumb is focusable; arrow keys step it and show the value bubble while focused.
- The touch area is 44 pt tall regardless of the visual size.
Notes for AI
- Use Slider for one value and RangeSlider for a [low, high] pair. Both work controlled or uncontrolled.
- onValueChange fires during the drag; put requests and saves in onSlidingComplete.
- step={0} is continuous. showTicks only draws when there are 40 steps or fewer.
- Always pass accessibilityLabel and a formatValue that adds the unit.
- Leave room above the slider when showValue is 'drag': the bubble floats over the content above. 'always' reserves its own space.
- Requires GestureHandlerRootView at the app root.
Related
A − value + stepper whose value rolls in the direction of change. Hold a button to repeat with acceleration; the ends push back with a rubber-band bounce and a warning haptic. In a cart the − turns into a trash button at the minimum.
Two to five views of the same thing with an elastic highlight that stretches toward the new segment, can be dragged, and ticks at every boundary. Includes a billing toggle.