Stepper

Increment, decrement, or type a number in a bounded range. A − button, an editable numeric center field, and a + button, controlled by value and clamped to min / max by step. This is the ± numeric control (the iOS UIStepper idiom); for a multi-step progress indicator see Steps.
Pass label to title the control from above, and required to mark it: the label takes a decorative destructive star, and a screen reader hears the control as required, from aria-required on the web's numeric field and from its name ("Quantity, required") on iOS and Android.
iOS
Android
Web
tsx
<Stepper defaultValue={3} max={10} />

Props

Prop
Description
value
number
Controlled numeric value (clamped to [min, max] for display); omit for uncontrolled use.
defaultValue
number
Initial value for uncontrolled use (a bare <Stepper /> steps out of the box). Default `min`.
onChange
(next: number) => void
Fired with the next clamped value when buttons, adjustment keys, or direct entry change it (both modes).
testID
string
E2E hook forwarded to the group container.
min
number
Lower bound. Default 0. The − button disables when value <= min.
max
number
Upper bound. Default Number.MAX_SAFE_INTEGER. The + button disables when value >= max.
step
number
Increment/decrement amount for the ± buttons and adjustment keys. Default 1.
label
string
The control's persistent, component-owned label. When set it renders as a VISIBLE title ABOVE the ± control (mirroring Input's above-field placement, per-OS type from the skin) and becomes the group's programmatic name (wired via accessibilityLabel + aria-labelledby). When omitted, the control keeps the invisible "Number" accessible-name fallback and renders no visible label, so a bare `<Stepper />` looks exactly as before.
description
ReactNode
Optional muted secondary line rendered under the label (parity with Input). Takes effect only alongside `label`.
required
boolean
Marks the control required: appends a destructive "*" to the label (decorative, never in the accessible name) and announces the control as required, through aria-required on the web's numeric field and with the word in its name ("Quantity, required") on iOS and Android. The star takes effect only alongside `label`.
small
boolean
Size (pick one; default is the medium control). Precedence: large > small.
large
boolean
Size (pick one; default is the medium control). Precedence: large > small.
disabled
boolean
State.
style
LayoutStyle
Composition within a parent only, never a restyle hook and never a width: the parent layout container provides the bounds.
ref
React.Ref<RNTextInput>
Ref to the underlying React Native host. Supports object refs and callback refs; native methods follow the platform's behavior.

Do & Don’t

Bounds

Don’t
Leaving the range unbounded lets the user push the count below zero or past what the form can accept.
Do
Quantity
Set min and max so the buttons disable at the edges and the value can never leave the valid range.

Step

Don’t
A step of 1 on a field that only takes round numbers makes the user tap many times to reach a usable value.
Do
Match step to the real increment, so each tap moves the value by an amount that makes sense for the field.