Skip to content

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

  • controls shows stepper buttons by default; controls="false" hides them (keyboard ↑↓ stepping still works)
  • controls-position="right" (default): stacked arrows on the right side
  • controls-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.15 renders as 15%), currency:USD, unit:GB, etc., following the host locale
  • The formatted text is mirrored to aria-valuetext so 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):

js
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)

Create an autofocus input

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 } where value is a number or null (empty)
  • oas-clear: clear button click
  • oas-focus / oas-blur: dispatched when the inner input gains/loses focus, detail: { value } is the current committed value (number or null; 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 ​

AttributeDescriptionTypeDefault
alignNumber text alignment left/center/right (logical, RTL mirrored)string—
autofocusFocus the inner input after mountboolean—
clearableClear button when a value is present (returns to the empty-value state)boolean—
controlsStepper buttons visibility (shown by default; controls="false" hides them, keyboard ↑↓ still steps)——
controls-positionButton layout: right (default, stacked up/down on the right) / both (−/+ on both sides, stepper-counter form)——
decimal-separatorDecimal point character for display and typed parsing (locale-aware default; submitted value stays canonical)string—
disabledDisabledboolean—
formatIntl-style declarative format: percent (0.15→15%) / currency:USD / unit:GB, following the host localestring—
groupingThousands grouping display (group separators stripped on parse)boolean—
labelAccessible name (aria-label source; falls back to built-in "Number input" when unset)string—
maxRange, out-of-range values are clamped automaticallystring—
minRange, out-of-range values are clamped automaticallystring—
placeholderPlaceholder (participates in the aria-label fallback chain)string—
precisionNumber of decimal placesstring—
prefix-textInline prefix text (slot="prefix" accepts any content; not part of value parsing)string—
readonlyRead-only: focusable, copyable, submittable; buttons disabled + aria-readonly, keyboard/wheel cannot change the valueboolean—
requiredRequired marker (drives the native valueMissing validation chain; not passed through to the inner input)boolean—
scrubNumeric 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 pointersstringtrue
sizeSize preset sm / md (default) / lg: control height and font scale——
statusValidation status: error / warning / success semantic border colors——
stepStepstring1
step-strictlyStrict stepping: committed value snaps to the nearest step multipleboolean—
suffix-textInline suffix text (slot="suffix" likewise)string—
valueCurrent value (controlled)string—
variantVisual variant outlined/filled/borderless (aligned with input)string—
wheelWheel stepping while focused (up increments, down decrements; off by default to prevent accidental changes)boolean—

Property (JS property; see each row for attribute reflection) ​

PropertyDescriptionTypeDefault
valueCurrent value: the live-parsed numeric string (empty / invalid input yields an empty string)string—

Events ​

EventDescription
oas-blurDispatched on blur after the commit, detail: { value } carries the committed value
oas-changeChange on step or blur, detail: { value } (number; null in the empty state)
oas-clearFires when the clear button is clicked (value returns to the empty state), detail: {}
oas-focusDispatched on focus, detail: { value } (current committed value)
oas-inputDispatched on every keystroke, detail: { value } is the current display text (uncommitted)

Slots ​

NameDescription
prefixPrefix content slot (not part of value parsing)
suffixSuffix content slot (not part of value parsing)

CSS Variables ​

CSS VariableDefault
--oas-button-group-radiusvar(--oas-radius-md)
--oas-input-number-controls-pad28px
--oas-input-number-fontvar(--oas-font-size-md)
--oas-input-number-heightvar(--oas-control-height-md)

Released under the MIT OR Apache-2.0 License.