Fields
Number Field
A native number box with fully styleable step buttons.
When to use it: Use it for quantities such as guests, price, or count.
Example
import {
Label,
NumberField,
NumberFieldDecrement,
NumberFieldIncrement,
NumberFieldInput,
} from "@comp0/react";
import { ChevronDownIcon, ChevronUpIcon } from "@heroicons/react/16/solid";
export function Example() {
return (
<NumberField
className="flex max-w-xs flex-col gap-1.5"
defaultValue={2}
id="tickets"
max={10}
min={1}
name="tickets"
>
<Label className="text-base font-medium text-zinc-900 sm:text-sm dark:text-zinc-100">
Tickets
</Label>
<div className="flex overflow-hidden rounded border border-zinc-950/10 bg-white focus-within:outline-2 focus-within:outline-teal-600 dark:border-white/10 dark:bg-zinc-900 dark:focus-within:outline-teal-400">
<NumberFieldInput className="min-w-0 flex-1 [appearance:textfield] bg-transparent px-3 py-2.5 text-base text-zinc-950 outline-none sm:py-2 sm:text-sm dark:text-zinc-50 [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none" />
<div className="grid w-9 shrink-0 grid-rows-2 border-l border-zinc-950/10 dark:border-white/10">
<NumberFieldIncrement
aria-label="Increase tickets"
className="flex items-center justify-center border-b border-zinc-950/10 text-zinc-500 outline-none hover:bg-zinc-100 hover:text-zinc-900 focus-visible:bg-teal-50 focus-visible:text-teal-800 disabled:opacity-35 dark:border-white/10 dark:text-zinc-400 dark:hover:bg-zinc-800 dark:hover:text-zinc-100 dark:focus-visible:bg-teal-950 dark:focus-visible:text-teal-200"
>
<ChevronUpIcon className="size-3.5" aria-hidden="true" />
</NumberFieldIncrement>
<NumberFieldDecrement
aria-label="Decrease tickets"
className="flex items-center justify-center text-zinc-500 outline-none hover:bg-zinc-100 hover:text-zinc-900 focus-visible:bg-teal-50 focus-visible:text-teal-800 disabled:opacity-35 dark:text-zinc-400 dark:hover:bg-zinc-800 dark:hover:text-zinc-100 dark:focus-visible:bg-teal-950 dark:focus-visible:text-teal-200"
>
<ChevronDownIcon className="size-3.5" aria-hidden="true" />
</NumberFieldDecrement>
</div>
</div>
</NumberField>
);
}Anatomy
Dashed frames are invisible state providers; shaded shapes own real DOM. Numbered pins match the list below.
A wireframe sketch of the assembled component. Each numbered marker matches a part in the list that follows.
NumberField
Field provider and wrapper div. Owns a DOM element.
NumberFieldInput
Native number input for typing and form submission. Owns a DOM element.
NumberFieldIncrement
Native button that increases by one step. Owns a DOM element.
NumberFieldDecrement
Native button that decreases by one step. Owns a DOM element.
Step by step
- 1
Add the main part
Compose NumberFieldInput with increment and decrement buttons.
- 2
Add the supporting parts
Set min, max, and step on NumberField when the range matters.
- 3
Make the behavior clear
Name NumberField so its native input submits.
Exampletsx <NumberField name="guests" defaultValue={2} min={1}><NumberFieldInput /><NumberFieldIncrement /><NumberFieldDecrement /></NumberField>
Keyboard
- ↑
- Increases by step.
- ↓
- Decreases by step.
Forms and accessibility
NumberFieldInput submits as a named native number input. Step buttons use type="button" and default to tabIndex={-1} because Arrow keys provide the same keyboard operation on the input.
Accessibility checklist
- Label the number and its unit.
- Set min, max, and step when they convey a real limit.
- Keep the native input available for typing and Arrow key changes.
- Show validation feedback in text, not only color.
API reference
import { NumberField, NumberFieldInput, NumberFieldIncrement, NumberFieldDecrement } from "@comp0/react";NumberField
DOM elementField provider and wrapper div.
| Prop | Type | Description |
|---|---|---|
value | number | Controlled number. |
defaultValue | number | Initial number. |
onChange | (value: number) => void | Receives the next number. |
min / max / step | number | Range limits shared by the input and buttons. |
name | string | Submission name. |
disabled / invalid / required | boolean | Field-wide states. |
NumberFieldInput
DOM elementNative number input for typing and form submission.
| Prop | Type | Description |
|---|---|---|
HTML input props | InputHTMLAttributes | Forwards native input attributes. |
NumberFieldIncrement
DOM elementNative button that increases by one step.
| Prop | Type | Description |
|---|---|---|
aria-label | string | Defaults to "Increase value". |
NumberFieldDecrement
DOM elementNative button that decreases by one step.
| Prop | Type | Description |
|---|---|---|
aria-label | string | Defaults to "Decrease value". |
Style hooks
Attributes that appear while a state is true. Target them with Tailwind data variants such as data-open:bg-zinc-100, or with any CSS selector.
[data-invalid]on NumberField
- The value is invalid.
[data-disabled]on NumberField / NumberFieldIncrement / NumberFieldDecrement
- The field is disabled or a step is unavailable at its boundary.