|Kit

Number Input

A numeric input with increment / decrement steppers on Ark UI's NumberInput machine — clamping, locale-aware formatting, mouse-wheel, and the full keyboard model on the shared input shell.

NumberInput is a numeric <input> with spin buttons, built on Ark UI's NumberInput machine and the same shell as Input. It clamps to a range, formats with Intl.NumberFormat, supports the mouse wheel, and ships the full keyboard model ( / step, PageUp / PageDown jump, Home / End to min / max).

import { NumberInput } from '@42/ui-react/number-input';

<NumberInput defaultValue={3} min={0} max={10} />

The value is a real number (or null for empty) — the machine speaks strings internally, but value / defaultValue take a number | null and onChange hands one back, null whenever the field has no valid number. Like the rest of the family it carries its own label, description, error, and required — no external wrapper needed — and passing error flips it to the invalid (red) state. Omit them and it still composes cleanly inside a Field.

Playground

Component

SpinnerLoading preview

Props

Code

<Component  label="Slots"  size="md"  step={1}/>

Min, max & step

min / max clamp the range; step sets the spin amount. With allowMouseWheel, scrolling over a focused input nudges the value too.

Formatting

formatOptions is forwarded straight to Intl.NumberFormat, so currency, percent, and unit display come for free — the parsed value stays a plain number.

Sizes

Five heights — xs through xl — matching the rest of the family. The control font, padding, and the steppers scale to match.

Code

<NumberInput size="xs" defaultValue={1} /><NumberInput size="sm" defaultValue={1} /><NumberInput size="md" defaultValue={1} /><NumberInput size="lg" defaultValue={1} /><NumberInput size="xl" defaultValue={1} />

No controls

hideControls drops the steppers for a plain numeric field — useful inside dense forms where the spin buttons would crowd the layout.

Clearable

clearable adds a clear (×) button once there's a value — the numeric analogue of Select's clearable. Clicking it resets the field to null. placeholder shows while the field is empty.

Colors

Like the rest of the form family, the resting input is palette-independent — only the focus ring references --c-solid, so each palette tints the focus state for free. See Colors.

Code

<NumberInput color="brand" defaultValue={1} /><NumberInput color="green" defaultValue={1} /><NumberInput color="purple" defaultValue={1} />

Invalid & disabled

invalid swaps the border and ring to red regardless of color (and sets aria-invalid). disabled dims the shell and blocks input; readOnly keeps full contrast but rejects edits.

Code

<NumberInput invalid defaultValue={5} /><NumberInput disabled defaultValue={5} /><NumberInput readOnly defaultValue={5} />

With label, description & error

label, description (helper text), and error are built in via Field — no external wrapper needed. Passing error flips the shell to the invalid (red) state; required adds the semantic flag and a red asterisk on the label.

How many evaluation slots to book.
Pick at least one

Code

<NumberInput label="Slots" description="How many evaluation slots to book." defaultValue={1} min={1} /><NumberInput label="Slots" required defaultValue={1} min={1} /><NumberInput label="Slots" error="Pick at least one" defaultValue={0} min={1} />

If you omit these props, the control still composes inside an outer Field, inheriting the field's invalid, disabled, and readOnly from context — so an error on the field flips the input red automatically.

Controlled

Drive the value from state. onChange hands you a number, or null while the field is empty or mid-edit.

'use client';
import { useState } from 'react';
import { NumberInput } from '@42/ui-react/number-input';

export function Slots() {
  const [value, setValue] = useState<number | null>(1);
  return <NumberInput value={value} onChange={setValue} clearable min={1} max={99} />;
}

Forms

A name wires the underlying input into native <form> submission and FormData — no controlled state required.

<form action={save}>
  <NumberInput name="slots" defaultValue={1} min={1} />
</form>

API

Prop

Type

Accessibility

  • Full NumberInput keyboard model from Ark: / step, PageUp / PageDown jump by a larger step, Home / End snap to min / max.
  • The input is role="spinbutton" with aria-valuemin / aria-valuemax / aria-valuenow / aria-valuetext wired from the machine.
  • invalid sets aria-invalid. Pass label / description / error for an accessible name and error text via the built-in Field, or compose inside an outer Field instead.
  • The steppers are real <button>s with Increment / Decrement labels; the wheel and scrub gestures are progressive enhancements over keyboard / typing.
  • suffix is decorative only — aria-hidden and non-selectable, never part of the editable value or the accessible name. To show a compact unit hint without a visible label, keep passing label (it stays the accessible name) and visually hide it with classNames={{ label: "sr-only" }}.

On this page