Skip to content
HHydro UIdocs
Navigate
ComponentsNumber Field
ImplementedForms / numeric input

Number Field

Edit a bounded number directly or with increment and decrement controls.

Interactive

Try it

value, min, max, step, disabled, readonly
-+
Live previewReady
MarkupStateEvents
<hui-number-field id="playground-number-field" name="quantity" min="0" max="10" step="1" value="3">
  <hui-number-field-decrement aria-label="Decrease quantity">-</hui-number-field-decrement>
  <hui-number-field-input aria-label="Quantity"></hui-number-field-input>
  <hui-number-field-increment aria-label="Increase quantity">+</hui-number-field-increment>
</hui-number-field>
data-state
Waiting for enhancement

No component events yet.

Usage

Use hui-number-field for bounded numeric values that benefit from direct editing and step buttons. Use a slider when users choose from a continuous range visually. Do not use it for formatted currency or arbitrary text without a numeric constraint model.

Anatomy

  • Root: hui-number-field
  • Input: hui-number-field-input with a native input[type="number"]
  • Increment/decrement controls: hui-number-field-increment, hui-number-field-decrement
  • State hooks: data-state, data-invalid, and data-disabled

Examples

Fixture exampleSource-backed
<section aria-labelledby="number-field-heading">
    <h2 id="number-field-heading">Quantity</h2>
    <form id="number-field-form">
      <hui-number-field id="quantity-field" name="quantity" min="0" max="10" step="1" value="3" aria-labelledby="number-field-heading">
        <hui-number-field-decrement aria-label="Decrease quantity">−</hui-number-field-decrement>
        <hui-number-field-input><b>Quantity</b></hui-number-field-input>
        <hui-number-field-increment aria-label="Increase quantity">+</hui-number-field-increment>
      </hui-number-field>
    </form>
  </section>

API reference

AttributeMeaning
valueCanonical committed numeric value. Values are clamped and rounded to the step grid.
default-valueSeeds value once when the component is enhanced if value is absent.
min / maxNumeric bounds; defaults are 0 and 100. A reversed range is repaired.
stepPositive step used for normalization and increment/decrement; defaults to 1.
disabledDisables the input and both buttons and removes the input from the tab order.
readonlyKeeps the input focusable but prevents editing and increment/decrement actions.
allow-emptyAllows an empty committed value; defaults to true. Set allow-empty="false" to restore the minimum on blur.
name / form / requiredNative form metadata copied to the inner input.
placeholderNative input placeholder shown when the field is empty.
aria-label / aria-labelledby / aria-describedbyAccessible naming inherited by the inner spinbutton.
value-textOptional string with {value} replacement or valueText formatter property.

The root exposes data-state="empty|valid", data-invalid while the user has an invalid transient edit, and data-disabled when disabled. It emits hui-value-change with { value: number | null } whenever the committed value changes. The value attribute is the source of truth and is serialized as a plain decimal string without unnecessary trailing zeroes.

The inner input owns the successful form value, so no hidden duplicate control is necessary. Its value property and value attribute are both synchronized for SSR and no-JavaScript form submission.

States and styling

StateContract and styling guidance
DefaultValid numeric value or an allowed empty input with step buttons available.
HoverUse --hui-color-interactive-hover for enabled step-button feedback.
ActiveUse --hui-color-interactive-active for pressed step-button feedback.
FocusKeep a visible input or button ring with --hui-color-focus-ring.
DisabledDisable the input and buttons and use --hui-color-disabled-background and --hui-color-disabled.
ErrorTransient invalid edits expose data-invalid; pair --hui-color-danger with an accessible error message.
State channel

Attributes are the source of truth. Style derived state with data-state, ARIA attributes, and the --hui-* token aliases.

Accessibility and keyboard support

  • ArrowUp increments by step; ArrowDown decrements by step.
  • Home commits min; End commits max.
  • Enter commits a valid edit and restores the canonical value for an invalid edit.
  • Blur commits a valid edit and restores the last committed value for an invalid edit. An empty edit remains empty when allow-empty is true (the default); when allow-empty="false" it becomes min.
  • Increment and decrement buttons commit one step while retaining focus on the clicked button.
  • Buttons are disabled at the corresponding bound and while the root is disabled or readonly.
  • Modifier-key shortcuts are ignored. Wheel events do not change the value accidentally.
  • Disabled controls ignore all keyboard, pointer, and input interaction. Readonly controls remain focusable but do not accept edits or step actions.

SSR and forms

  • SSR emits a deterministic, clamped value when value or default-value is present and emits an empty native input otherwise when empty values are allowed.
  • role="spinbutton", aria-valuemin, aria-valuemax, aria-valuenow (when non-empty), aria-valuetext, aria-disabled, aria-readonly, and aria-required are resolved attributes, not only IDL state.
  • Existing projected nodes and consumer IDs are preserved through adoption. Internal IDs derive from the root ID when present; id-less fields do not create ARIA references.
  • SSR never installs input, keyboard, pointer, or blur listeners. No hydro markers or event attributes leak into serialized output.
  • default-value and default-* metadata are initialization seeds; after enhancement the canonical value attribute is authoritative.

Code

<form id="quantity-form">
  <hui-number-field
    id="quantity"
    name="quantity"
    min="0"
    max="10"
    step="1"
    value="3"
  >
    <hui-number-field-decrement
      aria-label="Decrease quantity"
    ></hui-number-field-decrement>
    <hui-number-field-input aria-label="Quantity"></hui-number-field-input>
    <hui-number-field-increment
      aria-label="Increase quantity"
    ></hui-number-field-increment>
  </hui-number-field>
</form>

The runtime shape is hui-number-field[data-hydro-root] > span > template tree, with projected part hosts retained in slots. The input part contains a native number input and the buttons contain native buttons. SSR writes the resolved spinbutton ARIA attributes, bounds, value, state, and native form attributes. Without JavaScript the native input remains editable and submits through the form, while custom buttons do not increment.

<hui-number-field id="playground-number-field" name="quantity" min="0" max="10" step="1" value="3">
  <hui-number-field-decrement aria-label="Decrease quantity">-</hui-number-field-decrement>
  <hui-number-field-input aria-label="Quantity"></hui-number-field-input>
  <hui-number-field-increment aria-label="Increase quantity">+</hui-number-field-increment>
</hui-number-field>