InputNumber
A numeric input component: text input with numeric keypad (inputmode="decimal"), stepper buttons, range constraints and formatted display, with full role="spinbutton" aria state.
Basic Usage
Basic usage
placeholder passes through to the inner input as a hint; when label is unset, the placeholder also participates in the accessible-name fallback chain (see the label section below).
Range & Step
min / max / step
The corresponding stepper button is automatically disabled when a boundary is reached. Typing an out-of-range value does not interrupt digit-by-digit input (typing 1 then 00 to reach 100 works); the value is corrected on blur with a temporary red border while out of range (see "Status & out-of-range hint").
Precision
precision
precision controls the number of decimal places for both display and committed values: 1.5 renders as 1.50, and stepping / blur correction keeps two decimals.
Sizes
size (sm / md / lg)
size has three tiers aligned with the global control tokens (--oas-control-height-* / --oas-font-size-*); default is md.
Stepper Buttons
controls visibility & controls-position
controlsshows stepper buttons by default;controls="false"hides them (keyboard ↑↓ stepping still works)controls-position="right"(default): stacked arrows on the right sidecontrols-position="both":- / +buttons on both sides — friendlier for touch counter scenarios
Press and hold a stepper button for 800ms to enter auto-repeat: it steps every 100ms until release (built-in behavior, no configuration needed).
Prefix & Suffix
prefix / suffix
prefix-text / suffix-text are inline decorative texts (not part of value parsing); same-named slots also accept arbitrary content: <span slot="prefix">…</span>. prefix / suffix are compatibility aliases (canonical: prefix-text / suffix-text), usable through both the attribute and property channels (React / Vue bindings included).
clearable + controls + suffix stacked
clearable / stepper controls / affixes compose freely: right-side elements lay out left-to-right as suffix → clear button → steppers, all embedded inside the input box, and the entered text yields by the combined width (controls-position="both" keeps the clear button / suffix inside the box, clear of the right + button).
Grouping & Declarative Formatting
grouping (thousands separator)
format currency / percent / unit
grouping: thousands grouping for display (separators are stripped when parsing)format: Intl-style declarative formatting —percent(ratio semantics:0.15renders as15%),currency:USD,unit:GB, etc., following the host locale- The formatted text is mirrored to
aria-valuetextso screen readers announce it
Function Formatting
formatter / parser function properties
Attributes cannot carry functions; pair them via JS properties (takes precedence over the declarative format attributes):
el.formatter = (v) => `≈ ${v.toLocaleString()} pcs`
el.parser = (s) => Number(s.replace(/[^0-9.\-]/g, ''))A parser returning a non-finite number is treated as invalid input (reverts to the last valid value on blur). The demo above is wired in the unified script block at the bottom of this page.
Empty Value & Clearable
clearable & empty value semantics
"Unfilled" ≠ "0": when value is empty (or unset) the component is in the empty state, oas-change dispatches detail.value === null, and form serialization yields an empty string. Once a value is entered, a clear button appears and returns to the empty state in one click (dispatching oas-clear + oas-change null). Stepping from empty starts at min (when set) or 0.
Status & Out-of-range Hint
status & temporary out-of-range highlight
status (error / warning / success) sets the semantic border color for form-validation wiring. In the fourth example, type 200 to see the temporary red border while out of range (input is not interrupted); it is corrected back to 100 on blur.
Strict Step
step-strictly
With step-strictly, committed values snap to the nearest multiple of step (whole-case / whole-dozen purchasing): typing 7 becomes 12 on blur; typing 5 becomes 0.
Readonly
readonly
readonly is distinct from disabled: focusable, copyable, submittable, but stepper buttons are disabled and keyboard / wheel cannot change the value (aria-readonly synced).
Wheel Stepping
wheel (off by default)
With wheel, scrolling while the input is focused steps the value (up increases, down decreases) and prevents page scrolling; off by default to avoid accidental triggers.
Pointer Scrubbing
Press-drag the numeric area (scrub) + Shift/Alt fine steps
The numeric area supports pointer scrubbing: press and drag the input horizontally — 4px per step (step size = step) — no precise clicking or typing needed in dense tuning. Modifier keys share the knob convention: Shift for fine adjustment (×0.2), Alt for ultra-fine (×0.04); no acceleration tier. Dragging back to the press point restores the original value (mistaken drags are losslessly undone); movement under one step counts as a plain click (focus and text selection unaffected). Release commits per the commit-based model (oas-change, not dispatched when the value is unchanged), and dragging dispatches oas-input.
Scrubbing is not enabled on coarse pointers (tap focuses and raises the keyboard — typing wins); CSS already permits vertical touch scrolling (touch-action: pan-y) so only horizontal movement enters scrub. Set scrub="false" to disable entirely.
Disabled
Disabled
Accessible Name (label)
label (accessible name)
label serves as the accessible name (aria-label) for the input: once set, screen readers announce it; when unset, it falls back to placeholder, then to the built-in text "Number input". The stepper buttons "Increase / Decrease" also use built-in text for their accessible names.
Decimal Separator (decimal-separator)
decimal-separator (locale-aware by default)
decimal-separator sets the decimal point character (defaults to the runtime locale's decimal separator, same source as Intl formatting). The left one uses the locale default; the right one explicitly uses a comma: display, typed parsing, and committed value stay consistent — typing 2,5 commits 2.5 and re-renders as 2,5 on blur. Listen to oas-change to read the committed number.
Variants
variant (outlined / filled / borderless)
variant supports outlined (default border) / filled (filled background, border only on focus) / borderless (no border, no background), with the same semantics as the oas-input variants; with controls-position="both" the −/+ buttons follow the variant too.
Alignment (align)
align (left / center / right)
align controls the number text alignment (left / center / right). For RTL safety it maps to logical text-align: start/end: left / right mirror automatically to the line start/end under dir="rtl". When unset, the browser default applies (start, i.e. left-aligned in LTR).
Autofocus
autofocus (focus the inner input after mount)
autofocus forwards focus to the inner input after mount (native autofocus does not pierce the shadow DOM), so a page/form can be typed into immediately. To avoid stealing focus on page load, this demo creates a component with autofocus via a button.
Events
Change / clear / focus / blur / input events
oas-change: fires on blur / Enter / step / wheel / clear,detail: { value }wherevalueis a number ornull(empty)oas-clear: clear button clickoas-focus/oas-blur: dispatched when the inner input gains/loses focus,detail: { value }is the current committed value (number ornull; blur fires after the commit and carries the new value)oas-input: dispatched on every keystroke,detail: { value }is the current display text (string, uncommitted semantics; includes format decorations in formatted scenarios)
required
required (native validation chain)
required drives the native validation chain (form-associated): when unfilled, checkValidity() returns false (valueMissing) and native form submission is blocked; it recovers to :valid once filled.
Programmatic read/write of the current value goes through the public value property: el.value reads the FormData-equivalent value (the real-time parsed value while the inner input is present; empty string for empty/invalid typing); el.value = x writes the controlled value attribute and force-refreshes the inner control (ignoring focus protection) without dispatching events.
API
oas-input-number
Attributes
| Attribute | Description | Type | Default |
|---|---|---|---|
align | Number text alignment left/center/right (logical, RTL mirrored) | string | — |
autofocus | Focus the inner input after mount | boolean | — |
clearable | Clear button when a value is present (returns to the empty-value state) | boolean | — |
controls | Stepper buttons visibility (shown by default; controls="false" hides them, keyboard ↑↓ still steps) | — | — |
controls-position | Button layout: right (default, stacked up/down on the right) / both (−/+ on both sides, stepper-counter form) | — | — |
decimal-separator | Decimal point character for display and typed parsing (locale-aware default; submitted value stays canonical) | string | — |
disabled | Disabled | boolean | — |
format | Intl-style declarative format: percent (0.15→15%) / currency:USD / unit:GB, following the host locale | string | — |
grouping | Thousands grouping display (group separators stripped on parse) | boolean | — |
label | Accessible name (aria-label source; falls back to built-in "Number input" when unset) | string | — |
max | Range, out-of-range values are clamped automatically | string | — |
min | Range, out-of-range values are clamped automatically | string | — |
placeholder | Placeholder (participates in the aria-label fallback chain) | string | — |
precision | Number of decimal places | string | — |
prefix-text | Inline prefix text (slot="prefix" accepts any content; not part of value parsing) | string | — |
readonly | Read-only: focusable, copyable, submittable; buttons disabled + aria-readonly, keyboard/wheel cannot change the value | boolean | — |
required | Required marker (drives the native valueMissing validation chain; not passed through to the inner input) | boolean | — |
scrub | Numeric pointer scrubbing (on by default): press and drag the input horizontally — 4px per step (step size = step); Shift for fine (×0.2), Alt for ultra-fine (×0.04); drag back to the press point to restore the original value; movement under one step counts as a plain click (typing/text selection preserved); commits on release (oas-change); scrub="false" disables; not enabled on coarse pointers | string | true |
size | Size preset sm / md (default) / lg: control height and font scale | — | — |
status | Validation status: error / warning / success semantic border colors | — | — |
step | Step | string | 1 |
step-strictly | Strict stepping: committed value snaps to the nearest step multiple | boolean | — |
suffix-text | Inline suffix text (slot="suffix" likewise) | string | — |
value | Current value (controlled) | string | — |
variant | Visual variant outlined/filled/borderless (aligned with input) | string | — |
wheel | Wheel stepping while focused (up increments, down decrements; off by default to prevent accidental changes) | boolean | — |
Property (JS property; see each row for attribute reflection)
| Property | Description | Type | Default |
|---|---|---|---|
value | Current value: the live-parsed numeric string (empty / invalid input yields an empty string) | string | — |
Events
| Event | Description |
|---|---|
oas-blur | Dispatched on blur after the commit, detail: { value } carries the committed value |
oas-change | Change on step or blur, detail: { value } (number; null in the empty state) |
oas-clear | Fires when the clear button is clicked (value returns to the empty state), detail: {} |
oas-focus | Dispatched on focus, detail: { value } (current committed value) |
oas-input | Dispatched on every keystroke, detail: { value } is the current display text (uncommitted) |
Slots
| Name | Description |
|---|---|
prefix | Prefix content slot (not part of value parsing) |
suffix | Suffix content slot (not part of value parsing) |
CSS Variables
| CSS Variable | Default |
|---|---|
--oas-button-group-radius | var(--oas-radius-md) |
--oas-input-number-controls-pad | 28px |
--oas-input-number-font | var(--oas-font-size-md) |
--oas-input-number-height | var(--oas-control-height-md) |