Skip to content

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.

On this page

Example

Number Field.tsxtsx
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.

  1. NumberField

    Field provider and wrapper div. Owns a DOM element.

  2. NumberFieldInput

    Native number input for typing and form submission. Owns a DOM element.

  3. NumberFieldIncrement

    Native button that increases by one step. Owns a DOM element.

  4. NumberFieldDecrement

    Native button that decreases by one step. Owns a DOM element.

Step by step

  1. 1

    Add the main part

    Compose NumberFieldInput with increment and decrement buttons.

  2. 2

    Add the supporting parts

    Set min, max, and step on NumberField when the range matters.

  3. 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

Importtsx
import { NumberField, NumberFieldInput, NumberFieldIncrement, NumberFieldDecrement } from "@comp0/react";

NumberField

DOM element

Field provider and wrapper div.

PropTypeDescription
valuenumberControlled number.
defaultValuenumberInitial number.
onChange(value: number) => voidReceives the next number.
min / max / stepnumberRange limits shared by the input and buttons.
namestringSubmission name.
disabled / invalid / requiredbooleanField-wide states.

NumberFieldInput

DOM element

Native number input for typing and form submission.

PropTypeDescription
HTML input propsInputHTMLAttributesForwards native input attributes.

NumberFieldIncrement

DOM element

Native button that increases by one step.

PropTypeDescription
aria-labelstringDefaults to "Increase value".

NumberFieldDecrement

DOM element

Native button that decreases by one step.

PropTypeDescription
aria-labelstringDefaults 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.

Keep exploring