NumberInput
A number input; input capabilities match TextInput.
Basic usage
The value type is number | '' — clearing the input or typing non-numeric content means no value.
Stepping
Three stepping channels; the everyday step is buttonStep:
- Plus/minus buttons:
showButtons(on by default) renders a button on each side. They are purely decorative (aria-hidden, outside the tab order), and clicking them never steals focus from the input; they are disabled whendisabledorreadOnly. - Keyboard: ↑/↓ steps by
buttonStep; PgUp/PgDn steps bypageStep(10 ×buttonStepby default). - Mouse wheel: only while the input is focused (scroll up to increase, down to decrease), and page scrolling is prevented; hovering without focus never intercepts the wheel, so scrolling the page won't change the value by accident.
Stepping converges the value: the result is clamped into [min, max] and snapped to a multiple of step; when the current value is empty (''), stepping starts from 0. Convergence happens on stepping only — values typed out of range or off-step are kept as typed and flagged by soft validation.
Range and step
min/max: the valid range, also written as the<input>'smin/maxattributes.step: the validity step — the value must be a multiple of it to count as valid; by default decimals are unrestricted (the attribute outputsstep="any").buttonStep: the actual step for buttons / arrow keys / wheel, defaulting tostep(then 1).pageStep: the PgUp/PgDn step, defaulting to 10 ×buttonStep.
Soft validation
Validity is built in. When the value fails, the input element gets aria-invalid and the root gets an invalid flag class, but the value is not rewritten:
- Empty value: invalid when
required, validated right on mount (empty + required is flagged red as soon as it loads); - Non-finite numbers, values that are not a multiple of
step, values outside[min, max].
The timing matches TextInput's soft validation: on value change (debounced), on blur, cleared on focus; changing min/max/step/required re-validates immediately.
Label and icons
label / labelPosition / invisibleLabel work exactly as in TextInput; when indicator is not given explicitly and required is true, it falls back to the required indicator.
Where props land
The component root is a non-focusable <div> and the input element is an <input type="number"> wrapped in an oo-ui-numberInputWidget-field container (with buttons on, the root also carries oo-ui-numberInputWidget-buttoned). The landing rules are the same as TextInput:
...restfrom props lands on the root div; attributes that must go on the native<input>(such asrole,aria-*,autoComplete) go through theinputPropschannel, whoseonChange/onBlur/onFocusare chained after the component's own logic.inputRefpoints to the inner<input>(the componentrefpoints to the root div); useinputRefto focus the input.tabIndex,title,dir,accessKeyandnameare taken over by the component and land directly on the<input>(matching the original's landing spots), not viarest.
API
Differences from OOUI
- Non-positive
step/buttonStep/pageStepthrows at construction time in the original; here it logs a one-time development warning and renders with the given values. allowInteger/isIntegerare adopted for compatibility: turning them on is equivalent to forcingstep={1}, with a development warning suggesting migration (the original adopts them silently) — new code should usestepdirectly.
See also
- The single-line foundation (type whitelist,
validatesoft validation, etc.): TextInput - How values flow between the component and your state: Controlled and uncontrolled
- The pass-through and
refrules shared by all components: Common props