549 lines
15 KiB
Markdown
549 lines
15 KiB
Markdown
# Number Field
|
|
|
|
A number input that allow users to input custom number entries with a keyboard.
|
|
|
|
## Import
|
|
|
|
```
|
|
Copyts
|
|
import { NumberField } from "@kobalte/core/number-field";
|
|
// or
|
|
import { Root, Label, ... } from "@kobalte/core/number-field";
|
|
// or (deprecated)
|
|
import { NumberField } from "@kobalte/core";
|
|
```
|
|
|
|
```
|
|
Copyts
|
|
import { NumberField } from "@kobalte/core/number-field";
|
|
// or
|
|
import { Root, Label, ... } from "@kobalte/core/number-field";
|
|
// or (deprecated)
|
|
import { NumberField } from "@kobalte/core";
|
|
```
|
|
|
|
## Features
|
|
|
|
- Follows the [WAI ARIA Spinbutton](https://www.w3.org/WAI/ARIA/apg/patterns/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**: 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.
|
|
|
|
```
|
|
Copytsx
|
|
<NumberField>
|
|
<NumberField.Label />
|
|
<NumberField.Input />
|
|
<NumberField.HiddenInput />
|
|
<NumberField.IncrementTrigger />
|
|
<NumberField.DecrementTrigger />
|
|
<NumberField.Description />
|
|
<NumberField.ErrorMessage />
|
|
</NumberField>
|
|
```
|
|
|
|
```
|
|
Copytsx
|
|
<NumberField>
|
|
<NumberField.Label />
|
|
<NumberField.Input />
|
|
<NumberField.HiddenInput />
|
|
<NumberField.IncrementTrigger />
|
|
<NumberField.DecrementTrigger />
|
|
<NumberField.Description />
|
|
<NumberField.ErrorMessage />
|
|
</NumberField>
|
|
```
|
|
|
|
## Example
|
|
|
|
Quantity
|
|
|
|
ArrowArrow
|
|
|
|
index.tsxstyle.css
|
|
|
|
```
|
|
Copytsx
|
|
import { NumberField } from "@kobalte/core/number-field";
|
|
import "./style.css";
|
|
|
|
function App() {
|
|
return (
|
|
<NumberField class="number-field">
|
|
<NumberField.Label class="number-field__label">
|
|
Quantity
|
|
</NumberField.Label>
|
|
<div class="number-field__group">
|
|
<NumberField.Input class="number-field__input" />
|
|
<NumberField.IncrementTrigger aria-label="Increment" class="number-field__increment"><ArrowUpIcon/></NumberField.IncrementTrigger>
|
|
<NumberField.DecrementTrigger aria-label="Decrement" class="number-field__decrement"><ArrowDownIcon/></NumberField.DecrementTrigger>
|
|
</div>
|
|
</NumberField>
|
|
);
|
|
}
|
|
```
|
|
|
|
```
|
|
Copytsx
|
|
import { NumberField } from "@kobalte/core/number-field";
|
|
import "./style.css";
|
|
|
|
function App() {
|
|
return (
|
|
<NumberField class="number-field">
|
|
<NumberField.Label class="number-field__label">
|
|
Quantity
|
|
</NumberField.Label>
|
|
<div class="number-field__group">
|
|
<NumberField.Input class="number-field__input" />
|
|
<NumberField.IncrementTrigger aria-label="Increment" class="number-field__increment"><ArrowUpIcon/></NumberField.IncrementTrigger>
|
|
<NumberField.DecrementTrigger aria-label="Decrement" class="number-field__decrement"><ArrowDownIcon/></NumberField.DecrementTrigger>
|
|
</div>
|
|
</NumberField>
|
|
);
|
|
}
|
|
```
|
|
|
|
## Usage
|
|
|
|
### Default value
|
|
|
|
An initial, uncontrolled value can be provided using the `defaultValue` prop.
|
|
|
|
Quantity
|
|
|
|
ArrowArrow
|
|
|
|
```
|
|
Copytsx
|
|
<NumberField defaultValue={40}>
|
|
<NumberField.Label>Quantity</NumberField.Label>
|
|
<div>
|
|
<NumberField.Input />
|
|
<NumberField.IncrementTrigger />
|
|
<NumberField.DecrementTrigger />
|
|
</div>
|
|
</NumberField>
|
|
```
|
|
|
|
```
|
|
Copytsx
|
|
<NumberField defaultValue={40}>
|
|
<NumberField.Label>Quantity</NumberField.Label>
|
|
<div>
|
|
<NumberField.Input />
|
|
<NumberField.IncrementTrigger />
|
|
<NumberField.DecrementTrigger />
|
|
</div>
|
|
</NumberField>
|
|
```
|
|
|
|
### 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
|
|
|
|
ArrowArrow
|
|
|
|
Quantity: 40. Raw: 40.
|
|
|
|
```
|
|
Copytsx
|
|
import { createSignal } from "solid-js";
|
|
|
|
function ControlledExample() {
|
|
const [value, setValue] = createSignal("40");
|
|
const [rawValue, setRawValue] = createSignal<number>();
|
|
|
|
return (
|
|
<>
|
|
<NumberField
|
|
value={value()}
|
|
onChange={setValue}
|
|
rawValue={rawValue()}
|
|
onRawValueChange={setRawValue}
|
|
>
|
|
<NumberField.Label>Quantity</NumberField.Label>
|
|
<div>
|
|
<NumberField.Input />
|
|
<NumberField.IncrementTrigger />
|
|
<NumberField.DecrementTrigger />
|
|
</div>
|
|
</NumberField>
|
|
<p>
|
|
Quantity: {value()}. Raw: {rawValue()}.
|
|
</p>
|
|
</>
|
|
);
|
|
}
|
|
```
|
|
|
|
```
|
|
Copytsx
|
|
import { createSignal } from "solid-js";
|
|
|
|
function ControlledExample() {
|
|
const [value, setValue] = createSignal("40");
|
|
const [rawValue, setRawValue] = createSignal<number>();
|
|
|
|
return (
|
|
<>
|
|
<NumberField
|
|
value={value()}
|
|
onChange={setValue}
|
|
rawValue={rawValue()}
|
|
onRawValueChange={setRawValue}
|
|
>
|
|
<NumberField.Label>Quantity</NumberField.Label>
|
|
<div>
|
|
<NumberField.Input />
|
|
<NumberField.IncrementTrigger />
|
|
<NumberField.DecrementTrigger />
|
|
</div>
|
|
</NumberField>
|
|
<p>
|
|
Quantity: {value()}. Raw: {rawValue()}.
|
|
</p>
|
|
</>
|
|
);
|
|
}
|
|
```
|
|
|
|
### Description
|
|
|
|
The `NumberField.Description` component can be used to associate additional help text with a number field.
|
|
|
|
Quantity
|
|
|
|
ArrowArrow
|
|
|
|
Choose a quantity.
|
|
|
|
```
|
|
Copytsx
|
|
<NumberField>
|
|
<NumberField.Label>Quantity</NumberField.Label>
|
|
<div>
|
|
<NumberField.Input />
|
|
<NumberField.IncrementTrigger />
|
|
<NumberField.DecrementTrigger />
|
|
</div>
|
|
<NumberField.Description>Choose a quantity.</NumberField.Description>
|
|
</NumberField>
|
|
```
|
|
|
|
```
|
|
Copytsx
|
|
<NumberField>
|
|
<NumberField.Label>Quantity</NumberField.Label>
|
|
<div>
|
|
<NumberField.Input />
|
|
<NumberField.IncrementTrigger />
|
|
<NumberField.DecrementTrigger />
|
|
</div>
|
|
<NumberField.Description>Choose a quantity.</NumberField.Description>
|
|
</NumberField>
|
|
```
|
|
|
|
### 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).
|
|
|
|
Quantity
|
|
|
|
ArrowArrow
|
|
|
|
Hmm, I prefer 40.
|
|
|
|
```
|
|
Copytsx
|
|
import { createSignal } from "solid-js";
|
|
|
|
function ErrorMessageExample() {
|
|
const [rawValue, setRawValue] = createSignal<number>();
|
|
|
|
return (
|
|
<NumberField
|
|
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>
|
|
);
|
|
}
|
|
```
|
|
|
|
```
|
|
Copytsx
|
|
import { createSignal } from "solid-js";
|
|
|
|
function ErrorMessageExample() {
|
|
const [rawValue, setRawValue] = createSignal<number>();
|
|
|
|
return (
|
|
<NumberField
|
|
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>
|
|
);
|
|
}
|
|
```
|
|
|
|
### 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/>`.
|
|
|
|
Quantity
|
|
|
|
ArrowArrow
|
|
|
|
ResetSubmit
|
|
|
|
```
|
|
Copytsx
|
|
function HTMLFormExample() {
|
|
const onSubmit = (e: SubmitEvent) => {
|
|
// handle form submission.
|
|
};
|
|
|
|
return (
|
|
<form onSubmit={onSubmit}>
|
|
<NumberField name="quantity">
|
|
<NumberField.Label>Quantity</NumberField.Label>
|
|
<NumberField.HiddenInput />
|
|
<div>
|
|
<NumberField.Input />
|
|
<NumberField.IncrementTrigger />
|
|
<NumberField.DecrementTrigger />
|
|
</div>
|
|
</NumberField>
|
|
<div>
|
|
<button type="reset">Reset</button>
|
|
<button type="submit">Submit</button>
|
|
</div>
|
|
</form>
|
|
);
|
|
}
|
|
```
|
|
|
|
```
|
|
Copytsx
|
|
function HTMLFormExample() {
|
|
const onSubmit = (e: SubmitEvent) => {
|
|
// handle form submission.
|
|
};
|
|
|
|
return (
|
|
<form onSubmit={onSubmit}>
|
|
<NumberField name="quantity">
|
|
<NumberField.Label>Quantity</NumberField.Label>
|
|
<NumberField.HiddenInput />
|
|
<div>
|
|
<NumberField.Input />
|
|
<NumberField.IncrementTrigger />
|
|
<NumberField.DecrementTrigger />
|
|
</div>
|
|
</NumberField>
|
|
<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.
|
|
|
|
Quantity
|
|
|
|
-+
|
|
|
|
```
|
|
Copytsx
|
|
<NumberField>
|
|
<NumberField.Label>Quantity</NumberField.Label>
|
|
<div>
|
|
<NumberField.DecrementTrigger class="custom-trigger">-</NumberField.DecrementTrigger>
|
|
<NumberField.Input />
|
|
<NumberField.IncrementTrigger class="custom-trigger">+</NumberField.IncrementTrigger>
|
|
</div>
|
|
</NumberField>
|
|
```
|
|
|
|
```
|
|
Copytsx
|
|
<NumberField>
|
|
<NumberField.Label>Quantity</NumberField.Label>
|
|
<div>
|
|
<NumberField.DecrementTrigger class="custom-trigger">-</NumberField.DecrementTrigger>
|
|
<NumberField.Input />
|
|
<NumberField.IncrementTrigger class="custom-trigger">+</NumberField.IncrementTrigger>
|
|
</div>
|
|
</NumberField>
|
|
```
|
|
|
|
### Format
|
|
|
|
The value of the number field component can be formatted based on the [locale with the `I18NProvider`](https://kobalte.dev/docs/core/components/i18n-provider) and `formatOptions`. For more information see [React Spectrum NumberField](https://react-spectrum.adobe.com/react-spectrum/NumberField.html).
|
|
|
|
Price
|
|
|
|
ArrowArrow
|
|
|
|
```
|
|
Copytsx
|
|
<NumberField formatOptions={{ style: "currency", currency: "USD" }} defaultValue={4}>
|
|
<NumberField.Label>Price</NumberField.Label>
|
|
<div>
|
|
<NumberField.Input />
|
|
<NumberField.IncrementTrigger />
|
|
<NumberField.DecrementTrigger />
|
|
</div>
|
|
</NumberField>
|
|
```
|
|
|
|
```
|
|
Copytsx
|
|
<NumberField formatOptions={{ style: "currency", currency: "USD" }} defaultValue={4}>
|
|
<NumberField.Label>Price</NumberField.Label>
|
|
<div>
|
|
<NumberField.Input />
|
|
<NumberField.IncrementTrigger />
|
|
<NumberField.DecrementTrigger />
|
|
</div>
|
|
</NumberField>
|
|
```
|
|
|
|
### Autofill
|
|
|
|
The number field supports autofill through `NumberField.HiddenInput`.
|
|
|
|
```
|
|
Copytsx
|
|
<NumberField>
|
|
<NumberField.Label>Quantity</NumberField.Label>
|
|
<NumberField.HiddenInput />
|
|
<div>
|
|
<NumberField.Input />
|
|
<NumberField.IncrementTrigger />
|
|
<NumberField.DecrementTrigger />
|
|
</div>
|
|
</NumberField>
|
|
```
|
|
|
|
```
|
|
Copytsx
|
|
<NumberField>
|
|
<NumberField.Label>Quantity</NumberField.Label>
|
|
<NumberField.HiddenInput />
|
|
<div>
|
|
<NumberField.Input />
|
|
<NumberField.IncrementTrigger />
|
|
<NumberField.DecrementTrigger />
|
|
</div>
|
|
</NumberField>
|
|
```
|
|
|
|
## API Reference
|
|
|
|
### NumberField
|
|
|
|
`NumberField` is equivalent to the `Root` import from `@kobalte/core/number-field` (and deprecated `NumberField.Root`).
|
|
|
|
| Prop | Description |
|
|
| --- | --- |
|
|
| value | `string | number`<br> The controlled formatted value of the number field. |
|
|
| defaultValue | `string | number`<br> The default value when initially rendered. Useful when you do not need to control the value. |
|
|
| onChange | `(value: string) => void`<br> Event handler called when the value of the NumberField changes as a formatted value. |
|
|
| rawValue | `number`<br> The controlled raw value of the number field. |
|
|
| onRawValueChange | `(value: number) => void`<br> Event handler called when the value of the NumberField changes as a number. |
|
|
| minValue | `number`<br> The smallest value allowed in the number field, defaults to `Number.MIN_SAFE_INTEGER`. |
|
|
| maxValue | `number`<br> The largest value allowed in the number field, defaults to `Number.MAX_SAFE_INTEGER`. |
|
|
| step | `number`<br> Increment/Decrement step when using the triggers or the arrows on keyboard in the number field. |
|
|
| largeStep | `number`<br> Increment/Decrement step when using the Page UP/Down keys in the number field, defaults `10 * step`. |
|
|
| changeOnWheel | `boolean`<br> Whether to increment/decrement on wheel scroll inside the number field. |
|
|
| format | `boolean`<br> Whether to format the input value. |
|
|
| formatOptions | [`Intl.NumberFormatOptions`](https://github.com/microsoft/TypeScript/blob/353ccb7688351ae33ccf6e0acb913aa30621eaf4/src/lib/es2020.intl.d.ts#L243-L251)<br> Formating options for the value of the number field. |
|
|
| allowedInput | `RegExp`<br> Allowed input characters in the number field (only prevents onInput, not paste), defaults to locale and format characters. |
|
|
| name | `string`<br> The name of the NumberField.HiddenInput of the number field, used when submitting an HTML form. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#htmlattrdefname). |
|
|
| validationState | `'valid' | 'invalid'`<br> Whether the number field should display its "valid" or "invalid" visual styling. |
|
|
| required | `boolean`<br> Whether the user must fill the number field before the owning form can be submitted. |
|
|
| disabled | `boolean`<br> Whether the number field is disabled. |
|
|
| readOnly | `boolean`<br> Whether the number field items can be selected but not changed by the user. |
|
|
|
|
| Data attribute | Description |
|
|
| --- | --- |
|
|
| data-valid | Present when the number field is valid according to the validation rules. |
|
|
| data-invalid | Present when the number field is invalid according to the validation rules. |
|
|
| data-required | Present when the user must fill the number field before the owning form can be submitted. |
|
|
| data-disabled | Present when the number field is disabled. |
|
|
| data-readonly | Present 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
|
|
|
|
| Prop | Description |
|
|
| --- | --- |
|
|
| forceMount | `boolean`<br> Used to force mounting when more control is needed. Useful when controlling animation with SolidJS animation libraries. |
|
|
|
|
## Rendered elements
|
|
|
|
| Component | Default rendered element |
|
|
| --- | --- |
|
|
| `NumberField` | `div` |
|
|
| `NumberField.Label` | `label` |
|
|
| `NumberField.Input` | `input` |
|
|
| `NumberField.HiddenInput` | `input` |
|
|
| `NumberField.IncrementTrigger` | `button` |
|
|
| `NumberField.DecrementTrigger` | `button` |
|
|
| `NumberField.Description` | `div` |
|
|
| `NumberField.ErrorMessage` | `div` |
|
|
|
|
Previous[←Navigation Menu](https://kobalte.dev/docs/core/components/navigation-menu)Next[Pagination→](https://kobalte.dev/docs/core/components/pagination) |