# NumberInput A number field with stepper buttons, keyboard steps, formatting, wheel and scrub. ```ehtml Example import { NumberInput } from "@elements/ui/number-input"; ``` ## Parts | Part | What it is | |---|---| | `.number-input` | The root. | | `.number-input-scrub` | The scrub label. | | `.number-input-group` | The bordered control holding the input and buttons. | | `.number-input-input` | The text input, role=spinbutton. | | `.number-input-button` | Decrement and increment buttons. | | `.number-input-cursor` | The cursor drawn while a scrub holds pointer lock. | ## Attributes | Attribute | Type | Default | Description | |---|---|---|---| | `value` | `number \| null` (two-way) | `null` | The number; null when the input is empty. | | `min` | `number \| undefined` | `undefined` | Lowest value. Home goes here. | | `max` | `number \| undefined` | `undefined` | Highest value. End goes here. | | `step` | `number \| "any"` | `1` | Arrow and button step. "any" steps by 1. | | `smallStep` | `number` | `0.1` | Alt + arrow step. | | `largeStep` | `number` | `10` | Shift + arrow, PageUp and PageDown step. | | `snapOnStep` | `boolean` | `false` | Steps land on multiples of the step. | | `allowOutOfRange` | `boolean` | `false` | Typed values may stay outside min and max (marked invalid). | | `allowWheelScrub` | `boolean` | `false` | The mouse wheel steps while the input is focused and hovered. | | `format` | `Intl.NumberFormatOptions` | `{}` | Display format: currency, percent, unit, fraction digits, grouping. | | `locale` | `string` | `""` | Locale for formatting and parsing; empty uses the browser's. | | `buttons` | `"sides" \| "end" \| "none"` | `"sides"` | Minus and plus on each side, stacked chevrons at the end, or none. | | `size` | `"sm" \| "md" \| "lg"` | `"md"` | Height and type size from the control tokens. | | `scrubLabel` | `string` | `""` | A label above the input you drag to change the value. | | `scrubDirection` | `"horizontal" \| "vertical"` | `"horizontal"` | Which drag direction scrubs. | | `pixelSensitivity` | `number` | `2` | Pixels of drag per step. | | `teleportDistance` | `number` | `0` | How far the scrub cursor travels before it loops back; 0 loops at the window's edge. | | `placeholder` | `string` | `""` | Shown while empty. | | `name` | `string` | `""` | Submits the raw number with the form. | | `form` | `string` | `""` | The id of the form the value belongs to. | | `disabled` | `boolean` | `false` | Not interactive. | | `readonly` | `boolean` | `false` | Focusable and readable, not editable. | | `required` | `boolean` | `false` | The form will not submit while empty. | | `invalid` | `boolean` | `false` | Marks the field invalid. | | `incrementLabel` | `string` | `"Increase"` | The increment button's accessible name. | | `decrementLabel` | `string` | `"Decrease"` | The decrement button's accessible name. | | `roleDescription` | `string` | `"Number field"` | aria-roledescription on the input. | | `class` | `string` | `""` | Extra classes on the root. | | `attrs` | `Record` | `{}` | Attributes for the input: id, aria-label, data-\*. | | `onValueChange` | `(value: number \| null, details: NumberInputChangeDetails) => void` | `() => {}` | Every change, with details.reason, details.direction and details.cancel(). | | `onValueCommit` | `(value: number \| null, details: NumberInputCommitDetails) => void` | `() => {}` | When a change is final: blur, Enter, a key step, a button release, wheel or scrub end. | ## Keyboard | Keys | Action | |---|---| | `ArrowUp / ArrowDown` | Step up or down. | | `Shift + ArrowUp / ArrowDown` | Large step. | | `Alt + ArrowUp / ArrowDown` | Small step. | | `PageUp / PageDown` | Large step. | | `Home / End` | Go to min or max, when set. | | `Enter` | Formats, clamps and commits the typed value. | ## Data attributes | Attribute | Values | On | |---|---|---| | `data-disabled` | present when disabled | root, scrub, group, input, buttons, cursor | | `data-readonly` | present when read-only | root, scrub, group, input, buttons, cursor | | `data-required` | present when required | root, scrub, group, input, buttons, cursor | | `data-step-mismatch` | present while the value is off step from an explicit min; the form will not submit | root | | `data-invalid` | present when invalid or out of range | root, scrub, group, input, buttons, cursor | | `data-focused, data-filled, data-dirty, data-touched, data-valid` | inside a Field, mirror the Field's state | root, scrub, group, input, buttons, cursor | | `data-scrubbing` | present while scrubbing | root, scrub, group, input, buttons, cursor | | `data-buttons` | `"sides" \| "end" \| "none"` | group | | `data-direction` | `"up" \| "down"` | button | ## Accessibility - The input is role=spinbutton with aria-valuenow, aria-valuemin, aria-valuemax and aria-valuetext for formatted values. - The buttons are out of the tab order (the arrow keys do their job), named Increase and Decrease, and point at the input with aria-controls. - A value outside min and max sets aria-invalid. - The scrub label is the input's label, so it names the field too. ## See also - [Slider](slider): Pick a value or a range by dragging thumbs along a track, with full keyboard support. - [PasswordInput](password-input): A password field with a button that shows and hides what was typed. - [InputOTP](input-otp): A one-time code in separate slots, with paste, SMS autofill and a pattern. - [TagsInput](tags-input): Type a list of tags into one field: add, edit, delete and paste them from the keyboard. - [ColorPicker](color-picker): Pick a color with an area, channel sliders, inputs, swatches and the eye dropper. - [FileUpload](file-upload): Drop, paste or browse for files; see them listed with previews, sizes, errors and progress.