Kobalte.v0.12.5

Number Field

A number input that allow users to input custom number entries with a keyboard.

Import

ts
import { NumberField } from "@kobalte/core";
ts
import { NumberField } from "@kobalte/core";

Features

  • Follows the WAI ARIA Spinbutton design pattern.
  • Built with a native <input> element.
  • Visual and ARIA labeling support.
  • Required and invalid states exposed to assistive technology via ARIA.
  • Support for description and error message help text linked to the input via ARIA.
  • Syncs with form reset events.
  • Can be controlled or uncontrolled.
  • Supports increment and decrement buttons.
  • Format and localize input number and raw input.
  • Supports mouse wheel event and all keyboard events.
  • Supports browser autofill.

Anatomy

The number field consists of:

  • NumberField.Root: The root container for the number field.
  • NumberField.Label: The label that gives the user information on the number field.
  • NumberField.Input: The native HTML input of the number field, used for display number.
  • NumberField.HiddenInput: The native HTML input of the number field, used for raw number form submition.
  • NumberField.IncrementTrigger: The increment button of the number field.
  • NumberField.DecrementTrigger: The increment button of the number field.
  • NumberField.Description: The description that gives the user more information on the number field.
  • NumberField.ErrorMessage: The error message that gives the user information about how to fix a validation error on number field.
tsx
<NumberField.Root>
<NumberField.Label />
<NumberField.Input />
<NumberField.HiddenInput />
<NumberField.IncrementTrigger />
<NumberField.DecrementTrigger />
<NumberField.Description />
<NumberField.ErrorMessage />
</NumberField.Root>
tsx
<NumberField.Root>
<NumberField.Label />
<NumberField.Input />
<NumberField.HiddenInput />
<NumberField.IncrementTrigger />
<NumberField.DecrementTrigger />
<NumberField.Description />
<NumberField.ErrorMessage />
</NumberField.Root>

Example

Usage

Default value

An initial, uncontrolled value can be provided using the defaultValue prop.

tsx
<NumberField.Root defaultValue={40}>
<NumberField.Label>Quantity</NumberField.Label>
<div>
<NumberField.Input />
<NumberField.IncrementTrigger />
<NumberField.DecrementTrigger />
</div>
</NumberField.Root>
tsx
<NumberField.Root defaultValue={40}>
<NumberField.Label>Quantity</NumberField.Label>
<div>
<NumberField.Input />
<NumberField.IncrementTrigger />
<NumberField.DecrementTrigger />
</div>
</NumberField.Root>

Controlled value

The value and rawValue props can be used to make the value controlled. It is recommended to only use the rawValue as it is of type number. The onChange event is fired when the user type into the input and receive the new value. The onRawValueChange prop is called when the value changes and receives a number.

Quantity: 40. Raw: 40.

tsx
import { createSignal } from "solid-js";
function ControlledExample() {
const [value, setValue] = createSignal("40");
const [rawValue, setRawValue] = createSignal<number>();
return (
<>
<NumberField.Root
value={value()}
onChange={setValue}
rawValue={rawValue()}
onRawValueChange={setRawValue}
>
<NumberField.Label>Quantity</NumberField.Label>
<div>
<NumberField.Input />
<NumberField.IncrementTrigger />
<NumberField.DecrementTrigger />
</div>
</NumberField.Root>
<p>
Quantity: {value()}. Raw: {rawValue()}.
</p>
</>
);
}
tsx
import { createSignal } from "solid-js";
function ControlledExample() {
const [value, setValue] = createSignal("40");
const [rawValue, setRawValue] = createSignal<number>();
return (
<>
<NumberField.Root
value={value()}
onChange={setValue}
rawValue={rawValue()}
onRawValueChange={setRawValue}
>
<NumberField.Label>Quantity</NumberField.Label>
<div>
<NumberField.Input />
<NumberField.IncrementTrigger />
<NumberField.DecrementTrigger />
</div>
</NumberField.Root>
<p>
Quantity: {value()}. Raw: {rawValue()}.
</p>
</>
);
}

Description

The NumberField.Description component can be used to associate additional help text with a number field.

Choose a quantity.
tsx
<NumberField.Root>
<NumberField.Label>Quantity</NumberField.Label>
<div>
<NumberField.Input />
<NumberField.IncrementTrigger />
<NumberField.DecrementTrigger />
</div>
<NumberField.Description>Choose a quantity.</NumberField.Description>
</NumberField.Root>
tsx
<NumberField.Root>
<NumberField.Label>Quantity</NumberField.Label>
<div>
<NumberField.Input />
<NumberField.IncrementTrigger />
<NumberField.DecrementTrigger />
</div>
<NumberField.Description>Choose a quantity.</NumberField.Description>
</NumberField.Root>

Error message

The NumberField.ErrorMessage component can be used to help the user fix a validation error. It should be combined with the validationState prop to semantically mark the text field as invalid for assistive technologies.

By default, it will render only when the validationState prop is set to invalid, use the forceMount prop to always render the error message (ex: for usage with animation libraries).

Hmm, I prefer 40.
tsx
import { createSignal } from "solid-js";
function ErrorMessageExample() {
const [rawValue, setRawValue] = createSignal<number>();
return (
<NumberField.Root
onRawValueChange={setRawValue}
validationState={rawValue() !== 40 ? "invalid" : "valid"}
>
<NumberField.Label>Quantity</NumberField.Label>
<div>
<NumberField.Input />
<NumberField.IncrementTrigger />
<NumberField.DecrementTrigger />
</div>
<NumberField.ErrorMessage>Hmm, I prefer 40.</NumberField.ErrorMessage>
</NumberField.Root>
);
}
tsx
import { createSignal } from "solid-js";
function ErrorMessageExample() {
const [rawValue, setRawValue] = createSignal<number>();
return (
<NumberField.Root
onRawValueChange={setRawValue}
validationState={rawValue() !== 40 ? "invalid" : "valid"}
>
<NumberField.Label>Quantity</NumberField.Label>
<div>
<NumberField.Input />
<NumberField.IncrementTrigger />
<NumberField.DecrementTrigger />
</div>
<NumberField.ErrorMessage>Hmm, I prefer 40.</NumberField.ErrorMessage>
</NumberField.Root>
);
}

HTML forms

The number field name prop along with <NumberField.HiddenInput/> can be used for integration with HTML forms. Only the raw value is passed to the form.

If the formatted value is wanted (unrecommended) set the name attribute on <NumberField.Input/>.

tsx
function HTMLFormExample() {
const onSubmit = (e: SubmitEvent) => {
// handle form submission.
};
return (
<form onSubmit={onSubmit}>
<NumberField.Root name="quantity">
<NumberField.Label>Quantity</NumberField.Label>
<NumberField.HiddenInput />
<div>
<NumberField.Input />
<NumberField.IncrementTrigger />
<NumberField.DecrementTrigger />
</div>
</NumberField.Root>
<div>
<button type="reset">Reset</button>
<button type="submit">Submit</button>
</div>
</form>
);
}
tsx
function HTMLFormExample() {
const onSubmit = (e: SubmitEvent) => {
// handle form submission.
};
return (
<form onSubmit={onSubmit}>
<NumberField.Root name="quantity">
<NumberField.Label>Quantity</NumberField.Label>
<NumberField.HiddenInput />
<div>
<NumberField.Input />
<NumberField.IncrementTrigger />
<NumberField.DecrementTrigger />
</div>
</NumberField.Root>
<div>
<button type="reset">Reset</button>
<button type="submit">Submit</button>
</div>
</form>
);
}

Triggers

The number field supports optional increment/decrement triggers that are easily customizable.

tsx
<NumberField.Root>
<NumberField.Label>Quantity</NumberField.Label>
<div>
<NumberField.DecrementTrigger class="custom-trigger">-</NumberField.DecrementTrigger>
<NumberField.Input />
<NumberField.IncrementTrigger class="custom-trigger">+</NumberField.IncrementTrigger>
</div>
</NumberField.Root>
tsx
<NumberField.Root>
<NumberField.Label>Quantity</NumberField.Label>
<div>
<NumberField.DecrementTrigger class="custom-trigger">-</NumberField.DecrementTrigger>
<NumberField.Input />
<NumberField.IncrementTrigger class="custom-trigger">+</NumberField.IncrementTrigger>
</div>
</NumberField.Root>

Format

The value of the number field component can be formatted based on the locale with the I18NProvider and formatOptions. For more information see React Spectrum NumberField.

tsx
<NumberField.Root formatOptions={{ style: "currency", currency: "USD" }} defaultValue={4}>
<NumberField.Label>Price</NumberField.Label>
<div>
<NumberField.Input />
<NumberField.IncrementTrigger />
<NumberField.DecrementTrigger />
</div>
</NumberField.Root>
tsx
<NumberField.Root formatOptions={{ style: "currency", currency: "USD" }} defaultValue={4}>
<NumberField.Label>Price</NumberField.Label>
<div>
<NumberField.Input />
<NumberField.IncrementTrigger />
<NumberField.DecrementTrigger />
</div>
</NumberField.Root>

Autofill

The number field supports autofill through NumberField.HiddenInput.

tsx
<NumberField.Root>
<NumberField.Label>Quantity</NumberField.Label>
<NumberField.HiddenInput />
<div>
<NumberField.Input />
<NumberField.IncrementTrigger />
<NumberField.DecrementTrigger />
</div>
</NumberField.Root>
tsx
<NumberField.Root>
<NumberField.Label>Quantity</NumberField.Label>
<NumberField.HiddenInput />
<div>
<NumberField.Input />
<NumberField.IncrementTrigger />
<NumberField.DecrementTrigger />
</div>
</NumberField.Root>

API Reference

NumberField.Root

PropDescription
valuestring | number
The controlled formatted value of the number field.
defaultValuestring | number
The default value when initially rendered. Useful when you do not need to control the value.
onChange(value: string) => void
Event handler called when the value of the NumberField changes as a formatted value.
rawValuenumber
The controlled raw value of the number field.
onRawValueChange(value: number) => void
Event handler called when the value of the NumberField changes as a number.
minValuenumber
The smallest value allowed in the number field, defaults to Number.MIN_SAFE_INTEGER.
maxValuenumber
The largest value allowed in the number field, defaults to Number.MAX_SAFE_INTEGER.
stepnumber
Increment/Decrement step when using the triggers or the arrows on keyboard in the number field.
largeStepnumber
Increment/Decrement step when using the Page UP/Down keys in the number field, defaults 10 * step.
changeOnWheelboolean
Whether to increment/decrement on wheel scroll inside the number field.
formatboolean
Whether to format the input value.
formatOptionsIntl.NumberFormatOptions
Formating options for the value of the number field.
allowedInputRegExp
Allowed input characters in the number field (only prevents onInput, not paste), defaults to locale and format characters.
namestring
The name of the NumberField.HiddenInput of the number field, used when submitting an HTML form. See MDN.
validationState'valid' | 'invalid'
Whether the number field should display its "valid" or "invalid" visual styling.
requiredboolean
Whether the user must fill the number field before the owning form can be submitted.
disabledboolean
Whether the number field is disabled.
readOnlyboolean
Whether the number field items can be selected but not changed by the user.
Data attributeDescription
data-validPresent when the number field is valid according to the validation rules.
data-invalidPresent when the number field is invalid according to the validation rules.
data-requiredPresent when the user must fill the number field before the owning form can be submitted.
data-disabledPresent when the number field is disabled.
data-readonlyPresent when the number field is read only.

NumberField.Label, NumberField.Input, NumberField.HiddenInput, NumberField.Description and NumberField.ErrorMesssage share the same data-attributes.

NumberField.ErrorMessage

PropDescription
forceMountboolean
Used to force mounting when more control is needed. Useful when controlling animation with SolidJS animation libraries.

Rendered elements

ComponentDefault rendered element
NumberField.Rootdiv
NumberField.Labellabel
NumberField.Inputinput
NumberField.HiddenInputinput
NumberField.IncrementTriggerbutton
NumberField.DecrementTriggerbutton
NumberField.Descriptiondiv
NumberField.ErrorMessagediv