/// Inputs
NumberInput
Numeric field with a mono tabular value and a hairline stepper column — clamps to min/max and steps with the arrow keys.
import { NumberInput } from "@protocore/pds";Basics
A numeric control that renders the value in mono tabular figures with a +/- stepper column. It reports parsed numbers through onValueChange; give it an aria-label (or wrap it in a Field) so the spinbutton is named.
Bounds and step
min, max, and step govern both the arrow keys and the stepper buttons. Values clamp on step and on blur, and each stepper button disables when the value hits its edge.
Precision
Set precision to fix the number of decimals shown and to round the committed value — useful for rates, prices, and gwei-style quantities. Combine with a fractional step.
When to use
Use NumberInput for a *typed* number where nudging by a step is useful — replica counts, timeouts, gas prices, quantities.
- Picking a value from a bounded continuous range where the exact number matters less than the feel? Use a Slider.
- Just *displaying* a formatted currency figure? Use MoneyAmount — NumberInput is for editing, not read-only presentation.
- Free-form text that happens to contain digits (an ID, a version)? Use a plain Input.
Do & don't
Do
- Set min/max so the value can't leave its valid range.
- Use step (and a fractional step with precision) to match the quantity's granularity.
- Give it an aria-label or wrap it in a Field so the spinbutton is named.
- Use precision for money- and rate-style values that need fixed decimals.
Don't
- Don't use it for a continuous, feel-based range — that's a Slider.
- Don't use it to display read-only currency — that's MoneyAmount.
- Don't leave a bounded value unclamped; set min/max rather than validating after.
- Don't ship it unnamed — a bare spinbutton has no accessible label.
Accessibility
| Keys | Action |
|---|---|
| ArrowUp | Increment by `step` (clamped to `max`). |
| ArrowDown | Decrement by `step` (clamped to `min`). |
| Type | Edit the raw value; it parses and clamps on blur. |
- The field is a `role="spinbutton"` exposing `aria-valuenow`, `aria-valuemin`, and `aria-valuemax`.
- Give it an `aria-label` or a Field label — a spinbutton needs an accessible name.
- The +/- stepper buttons are `aria-hidden` and out of the tab order; keyboard users step with the arrows.
- `invalid` sets `aria-invalid` and the danger border.
NumberInput props
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | — | |
defaultValue | number | — | Initial value in uncontrolled mode. |
invalid | boolean | — | Mark the field invalid — danger border plus `aria-invalid`. |
max | number | — | Upper bound — clamped on blur/step; disables the + button at the ceiling. |
min | number | — | Lower bound — clamped on blur/step; disables the − button at the floor. |
onValueChange | ((value: number) => void) | — | Fires with the parsed number on edit and on step. |
precision | number | — | Fixed decimal places to display and round to on commit. |
size | enum | md | Control height: `sm` (32) · `md` (36, default) · `lg` (40). |
step | number | 1 | Step increment for the buttons and ArrowUp/Down. |
style | CSSProperties | — | |
value | number | — | Controlled numeric value. `undefined` = empty field. |