NumberStepper is the compact convenience preset built from NumberField. It combines a numeric text input with optional decrement and increment buttons. Import it from twenty-ui/components/input. Use NumberField when you need locale or formatting options, different modifier steps, scrubbing, or independent part composition.
Uncontrolled value
UsedefaultValue to set the initial quantity. The input owns subsequent changes.
Controlled value
Pass a number ornull through value and update it in onValueChange to own the same quantity in React state. The callback receives the next numeric value and event details.
null. Incomplete text such as - or + remains editable without reporting an invalid number until it is replaced or stepped. By default, parseable numeric edits report the bounded value; the displayed draft is normalized on blur. Values equal to the current value do not call onValueChange again.
onValueCommitted(value, details) reports the value after an edit is committed: on blur after typing or clearing, on pointer release after a button adjustment, and immediately for keyboard adjustments. Its details contain the native event and reason. onValueChange retains change details, including cancellation methods and the optional stepping direction.
Application validation
SetallowOutOfRange when the application needs the parsed value before applying its own limits or validation. onValueChange then receives typed and pasted numbers outside the range. Uncontrolled fields, or controlled fields that accept those values, preserve them on blur. Controlled fields that reject them return to their accepted value on blur. For example, replacing 60 with 45 reports 4 and then 45, even when min={30}. The application can ignore the intermediate value without accidentally saving the minimum.
Buttons and keyboard adjustments still stop at min and max. Native form validation prevents submission while an accepted value is outside that range. allowOutOfRange defaults to false.
Bounds and interaction
min and max are inclusive. Increment and decrement buttons stop at the matching bound. Arrow Up and Arrow Down adjust the focused input by step, which defaults to 1. Home and End select the corresponding bound when provided; call event.preventBaseUIHandler() in onKeyDown to keep a key’s text editing behavior instead. The same step applies when Shift or Alt is held. Displayed values support up to 15 fraction digits; use a positive step within that precision for decimal adjustments.
Values use Latin digits and show grouping separators from five integer digits, such as 12,500. Typed and pasted group separators of the browser’s locale are accepted.
step controls adjustments; it does not round typed values to a step. When min is set, native form validation also requires min plus a multiple of step: with the default step of 1, a typed 2.5 blocks submission. Set showButtons={false} for text editing with the same keyboard behavior.
Each button has a default accessible name. Use decrementLabel and incrementLabel to provide contextual or translated names. Give the input a visible Field.Label, aria-label, or aria-labelledby.
Forms and focus
Usename to include the numeric value in a form. form associates it with a form elsewhere in the document. The adjustment buttons use type="button", so adjusting a value does not submit the form. required participates in native validation.
Use a controlled value when your application needs to reset the field. A native form reset does not reset the numeric state.
disabled prevents changes and excludes the value from form submission. readOnly prevents changes while keeping the input focusable and its value available to the form.
Native input attributes and handlers, className, style, ref, and render apply to the visible text input. The ref receives an HTMLInputElement; call ref.current?.focus() to focus it. When composing through render, forward the supplied props and ref to a native input. Customize the surrounding layout with a separate element, or use the NumberField.Root and NumberField.Group parts when wrapper access is required. Combine the input with Field.Description and Field.Error for guidance and validation messages.
The preset deliberately uses compact styling, Latin digits, up to 15 fraction digits, grouping from five integer digits, and the same step for ordinary, Shift, and Alt adjustments. These choices apply only to NumberStepper. The full NumberField primitive retains Base UI’s formatting and stepping options.
Front component renderer
The React and Preact renderer sandboxes support typing, keyboard adjustments, bounds, form values, pointer stepping, and pasting over selected text. The renderer gallery verifies these interactions in both runtimes. As withNumberField, pointer adjustments report changes, but the sandbox does not currently deliver the corresponding commit callback on pointer release. Ordinary React hosts retain the complete commit behavior.
Props
boolean
default:"false"
Allows onValueChange to receive typed and pasted numbers outside the bounds. Native range validation still applies; buttons and keyboard adjustments remain bounded.
string
default:"Number field"
A user-friendly description of the input’s role for assistive tech. This is a role
description, not an accessible name — use
Field.Label or aria-label to name the control.string | ((state: NumberFieldInputState) => string | undefined)
Class applied to the visible input.
string
default:"Decrease value"
Accessible name for the decrement button.
number
Initial number when the field owns its value.
boolean
default:"false"
Disables the input and both buttons, and omits the form value.
string
ID of the form that owns the submitted numeric value.
string
ID of the visible input. Generated when omitted.
string
default:"Increase value"
Accessible name for the increment button.
number
Inclusive maximum. By default, onValueChange reports bounded numbers and out-of-range drafts normalize on blur.
number
Inclusive minimum. By default, onValueChange reports bounded numbers and out-of-range drafts normalize on blur.
string
Name of the numeric value submitted with a form.
((value: number | null, eventDetails: NumberFieldRootChangeEventDetails) => void)
Called with the next number or null and event details when the numeric value changes. Clearing reports null; incomplete text does not report a number.
((value: number | null, eventDetails: NumberFieldRootCommitEventDetails) => void)
Called with the committed number or null and generic event details after an edit is committed. Details contain the native event and reason, without change cancellation methods.
boolean
default:"false"
Prevents numeric changes while keeping the input focusable.
Ref<HTMLInputElement>
Ref to the visible input element.
ReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<DetailedHTMLProps<InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>, NumberFieldInputState>
Composes the visible text input with an element or render callback. Forward the supplied props and ref to an input. Use a separate element to customize the surrounding layout.
boolean
default:"false"
Requires a numeric value for native form submission.
boolean
default:"true"
Shows the decrement and increment buttons.
number
default:"1"
Amount added or subtracted by the buttons and arrow keys.
CSSProperties | ((state: NumberFieldInputState) => CSSProperties | undefined)
Inline styles applied to the visible input.
number | null
Controlled numeric value. Use null for an empty field.