Skip to content

HyNumberInput ​

Usage examples on this page are written for Lit / plain HTML (<hy-number-input>). The same component ships as HyNumberInput in @whitespaceux/harmony-react (native React 19), with typed wrappers for Angular, Solid, Svelte, and Vue. The API reference below applies to all frameworks.

A form-associated numeric stepper: a text field for typing an exact value, flanked by − / + buttons for click-or-hold increment. Pairs with hy-slider to give users both approximate (slider) and precise (number input) control over the same numeric field.

The primitive is deliberately general-purpose — value is a plain number, units are display-only (suffix), and DTCG / locale / composite values belong in consumer code. That keeps it equally useful for quantity pickers, dashboard bounds, Tuner token editors, and any future form builder.

A field or a settings row? ​

A field has its label above it, or beside it with layout="inline" (its helper and messages then sit under the control). A settings row — a setting's name with a line of description at the start and the control at the row's end, as on a preferences page — is a row of your own: a flex row with justify-content: space-between, the name and description as your own text, and the control named with aria-labelledby pointing at the name, with no label, helper-text or layout. Rebuilding a drawn settings page, keep the control at the row's end.

Form integration ​

Implements the Form-Associated Custom Elements API — value participates in FormData and validates against min, max, step, and required.

Keyboard ​

  • ArrowUp / ArrowDown: step by step
  • Shift + Arrow / PageUp / PageDown: step by shiftStep (10× by default)
  • Home / End: jump to min / max when finite
  • Enter: commit (blur-equivalent)

Pointer ​

Single click on ± steps by step (or shiftStep when Shift is held). Press-and-hold auto-repeats with an accelerating cadence. Release fires a single change. pointercancel and pointerleave stop the repeat.

When to use

  • An exact quantity with known bounds or steps: a count, a size, a percentage.
  • A value people nudge up and down from a known start.

Do

  • Set min, max and step to the values the field accepts.
  • Show the unit next to the value, in the label or with suffix.

When not to use

  • A value where the feel matters more than the number, such as volume or opacity: hy-slider.
  • Digits that are not a quantity, such as a phone number, postal code or ID: hy-text-input with the matching type.
  • A few fixed values, such as 1, 2 or 3 columns: hy-toggle-group or hy-select.
  • A date or a time: hy-date-field or hy-date-picker, never separate number fields.

Accessibility: your part ​

  • Name the field with label, or with aria-label / aria-labelledby on the host when nearby text already names it.

Examples ​

Basic quantity picker ​

html
<hy-number-input label="Quantity" min="1" max="99" value="1"></hy-number-input>

Fractional step with suffix ​

html
<hy-number-input label="Line height" min="0" max="2" step="0.01" value="1.5" suffix="em">
</hy-number-input>

Error state ​

html
<hy-number-input label="Bitrate" value="400" max="320" error-message="Exceeds license tier limit">
</hy-number-input>

Warning state ​

html
<hy-number-input label="Volume" value="95" max="100" warning-message="Loud: may damage hearing">
</hy-number-input>

Sized to its content — a 4-digit year ​

html
<hy-number-input label="Year" chars="4" min="1900" max="2100" value="2026"></hy-number-input>

Dense table variant (no visible buttons) ​

html
<hy-number-input size="small" hide-buttons value="12"></hy-number-input>

Pill shape ​

html
<hy-number-input pill value="5"></hy-number-input>

API ​

Properties ​

PropertyAttributeTypeDefaultDescription
valuevaluenumber0The current numeric value.
minminnumber—Minimum allowable value. Defaults to -Infinity (no lower bound).
maxmaxnumber—Maximum allowable value. Defaults to +Infinity (no upper bound).
stepstepnumber1Granularity between valid values.
shiftStepshift-stepnumber | undefined—Larger increment applied when Shift is held or PageUp/PageDown is pressed. Defaults to 10 × step.
displayPrecisiondisplay-precisionnumber | undefined—Decimal places to display and round to. When omitted, inferred from step (step=0.01 → 2). Set explicitly to over-ride the display precision without changing the step granularity.
disableddisabledbooleanfalseDisables all interaction.
readonlyreadonlybooleanfalseMakes the field non-editable. The stepper buttons stay in place — inert, out of the accessibility tree and painted quiet — so the field keeps its shape; aria-readonly on the input carries the state.
requiredrequiredbooleanfalseMarks the input as required for form validation.
errorerrorbooleanfalseWhether the input is in an error state.
warningwarningbooleanfalseWarning state: the value is accepted but worth a second look. Paints the warning color on the border at rest and shows warning-message; never sets aria-invalid and never touches validity. error wins when both are set.
namenamestring''The name attribute for form submission.
labellabelstring''Primary label above the control.
localelocalestring | undefined—BCP-47 locale for the number's digits and separators, shown and typed. Unset, the nearest lang (across shadow roots), else the browser's language. The value and the form value stay plain numbers.
hinthintstring''Secondary hint text under the label.
helperTexthelper-textstring''Helper text below the control.
errorMessageerror-messagestring''Error message (replaces the helper text). Setting it raises error, clearing it lowers it.
warningMessagewarning-messagestring''Warning message (replaces the helper text). Setting it raises warning, clearing it lowers it.
placeholderplaceholderstring''Placeholder shown when the field is empty.
prefixprefixstring''Display-only text before the number ("$", "CHF"). Not parsed. Rendered inside the field on the inline-start edge and read out with the value.
suffixsuffixstring''Display-only unit ("px", "%", "ms"). Not parsed. Rendered inside the field on the inline-end edge and read out with the value.
sizesize'small' | 'medium' | 'large''medium'Size variant. Aligns with hy-text-input / hy-select for form mixing.
layoutlayout'block' | 'inline''block'Row layout: block (default) stacks label above the control; inline puts label on the left and control on the right. Helper/error always sit under the control (col 2–end), never under the label. Set --hy-number-input-label-column-width on a wrapping container so stacked inputs align.
pillpillbooleanfalsePill shape — collapses the border radius to fully rounded ends.
hideButtonshide-buttonsbooleanfalseHide the ± stepper buttons. Keyboard stepping (ArrowUp/Down) still works. Useful in dense tables where buttons would add visual noise.
decreaseLabeldecrease-labelstring'Decrease {label}'Accessible name of the − stepper button (Decrease {label}); {label} is replaced by the field's label, and with no label the result is trimmed to Decrease. Use for internationalization.
increaseLabelincrease-labelstring'Increase {label}'Accessible name of the + stepper button (Increase {label}); {label} is replaced by the field's label, and with no label the result is trimmed to Increase. Use for internationalization.
charschars1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 10 | 12 | 16 | 20 | 24 | 32 | 48undefinedHow many characters the field holds — one of 1–8, 10, 12, 16, 20, 24, 32, 48. The input is that many 0 glyphs wide in its own font (1ch plus the value's letter-spacing), so the same markup holds the same count in every design system; the field padding, prefix / suffix and the ± buttons add on top, and the control never grows past its container. A value outside the set is ignored (dev warning).
inputIdinput-idstring''Explicit id for the underlying <input>; empty uses the fixed input (components.md "Ids").
autofocusautofocusbooleanfalseMarks this number input as the auto-focus target. Read by hy-dialog (and other overlay containers) on show to choose initial focus. Also focuses on first connect when used outside an overlay, mirroring native HTML autofocus but routed through JS so SSR'd HTML doesn't pull focus during hydration.
autoselectautoselectbooleanfalseAfter auto-focus lands, selects the current value so the user can type-to-replace. Pairs with autofocus for rename-style dialogs where the existing value is shown for context but is meant to be overwritten.
formatValue—(value: number) => string | undefined—Custom formatter for the field's display text when the input is not focused. When set, owns the full string — suffix is NOT appended. Does not affect value or FormData; only the visual representation. Must be a function, so assign as a property (el.formatValue = fn).
form—HTMLFormElement | null——
validity—ValidityState——
validationMessage—string——

Events ​

EventDetailDescription
input—Fired on every keystroke or step. Detail:
change—Fired on blur, Enter, or pointer release after stepping. Detail:

CSS Parts ​

PartDescription
baseThe component wrapper
labelThe label container (label + hint)
controlThe row containing −, input, +
inputThe native <input> element
decrementThe − button
incrementThe + button
helper-textThe helper text element
error-messageThe error message element
warning-messageThe warning message element
message-iconThe icon starting the error or warning message

CSS Custom Properties ​

The documented hooks. Every override hook the component reads — one per token it paints — is listed in @whitespaceux/harmony/theme-api.json, and @whitespaceux/harmony/component-bindings.json (the Harmony MCP get-bindings tool) says which part and state each one paints.

PropertyDefaultDescription
--hy-number-input-widthfit-contentHost width. Defaults to fit-content so the stepper hugs its value; set to 100% for full-row layouts. Still applies with chars: at 100% the field grows past its count to fill the row.
--hy-number-input-field-min-width—Minimum width of the input field. Defaults to 4ch; raise for ranges with long numbers (e.g. 8ch for 0–999999 or formatted currency). Not read while a valid chars is set — chars sizes the field instead, in every design system.
--hy-number-input-radius-form-mdvar(--hy-radius-form-md)Border radius
--hy-number-input-prefix-foreground-subtle-restvar(--hy-foreground-subtle-rest)The prefix text's color
--hy-number-input-radius-pill-mdvar(--hy-radius-pill-md)Border radius
--hy-number-input-gap-form-smvar(--hy-gap-form-sm)Gap between label, control, helper text
--hy-number-input-control-height-smvar(--hy-control-height-sm)Outer height for small size variant. Per-component override in the form-control height contract.
--hy-number-input-control-height-mdvar(--hy-control-height-md)Outer height for medium size variant.
--hy-number-input-control-height-lgvar(--hy-control-height-lg)Outer height for large size variant.
--hy-number-input-button-size—Stepper button width (defaults to control height)
--hy-number-input-padding-form-smvar(--hy-padding-form-sm)Inline padding inside the input column
--hy-number-input-background-resttransparentField background
--hy-number-input-background-surface-mediumvar(--hy-background-surface-medium)Stepper button background
--hy-number-input-background-surface-strongvar(--hy-background-surface-strong)Stepper button hover background
--hy-number-input-border-subtle-restvar(--hy-border-subtle-rest)Border color
--hy-number-input-border-default-hovervar(--hy-border-default-hover)Border color on hover
--hy-number-input-border-brand-restvar(--hy-border-brand-rest)Border color on focus
--hy-number-input-label-column-width—Width of the label column in layout="inline" mode. No default — set on a wrapping container so stacked inputs align.
--hy-number-input-stepper-foreground-faint-restvar(--hy-foreground-faint-rest)Stepper glyph color while readonly
--hy-number-input-stepper-foreground-icon-default-restvar(--hy-foreground-icon-default-rest)Stepper glyph color (the icon family, C9)
--hy-number-input-stepper-foreground-icon-default-disabledvar(--hy-foreground-icon-default-disabled)Stepper glyph color while disabled
--hy-number-input-foreground-danger-restvar(--hy-foreground-danger-rest)Error message text and icon color
--hy-number-input-foreground-warning-restvar(--hy-foreground-warning-rest)Warning message text and icon color
--hy-number-input-gap-layout-2xsvar(--hy-gap-layout-2xs)Gap between the message icon and its text
--hy-number-input-motion-transition-hover-durationvar(--hy-motion-transition-hover-duration)Transition duration for hover and focus state feedback
--hy-number-input-motion-transition-hover-easingvar(--hy-motion-transition-hover-easing)Transition easing for hover and focus state feedback

Methods ​

select() ​

Selects all text in the underlying input.

stepUp() ​

Increment the value by n steps (default 1). Clamps to max, fires input then change, and is a no-op when disabled or readonly.

stepDown() ​

Decrement the value by n steps (default 1). Clamps to min, fires input then change.

Built with Lit. Documented with VitePress.