Number Field

A number input with plus and minus buttons, keyboard stepping, min/max clamping, Intl formatting and drag-to-scrub labels.

Preview

Usage

import { z } from 'zod'
import { AutoForm } from '@vitnode/core/components/form/auto-form'
import { AutoFormNumber } from '@vitnode/core/components/form/fields/number'
const formSchema = z.object({
  guests: z.number().int().min(1).max(12).default(2),
})

<AutoForm
  formSchema={formSchema}
  fields={[
    {
      id: 'guests',
      component: props => (
        <AutoFormNumber {...props} label="Guests" max={12} min={1} unitLabel="people" />
      ),
    },
  ]}
/>

The form stores a real number, or null when cleared. Pass min/max to both: the schema validates, the props clamp.

Need an "unlimited" checkbox? Use Nullable Number.

Min, max and step

min/max disable the button at a limit and clamp typed values on blur. step is one press, largeStep adds Shift, smallStep adds

Alt. snapOnStep snaps to the nearest multiple.

<NumberField largeStep={50} max={500} min={0} snapOnStep step={5}>
  …
</NumberField>

Formatting

format takes Intl.NumberFormatOptions. The value stays a number: 0.15 shows as 15%. Formatting follows the app locale unless you pass locale.

<NumberField
  defaultValue={19.99}
  format={{ style: 'currency', currency: 'USD' }}
>
  …
</NumberField>

Scrub area

Drag the label in the preview sideways. NumberFieldScrubArea makes a label scrubbable. Pass the field's id as htmlFor so a click still focuses the input.

const id = React.useId()

<NumberField id={id} max={8} min={0}>
  <NumberFieldScrubArea htmlFor={id} label="Coffees per day" />
  <NumberFieldGroup>…</NumberFieldGroup>
</NumberField>

allowWheelScrub adds mouse-wheel changes while focused.

Sizes

<NumberField size="sm">…</NumberField>

Disabled and read-only

readOnly stays focusable, unlike disabled.

Accessibility

  • The input is a text field with inputMode, so $19.99 fits and phones show a number pad.
  • ↑ / ↓ step, Home / End jump to min / max when set.
  • The buttons are labelled "Increase" / "Decrease", skip Tab, and grow to a 44px hit area on touch.
  • Name the input with a label (htmlFor + id), a scrub area or aria-label. AutoFormNumber does it for you.

Props

Prop

Type

AutoFormNumber takes all of these except value, defaultValue and onValueChange (the form owns them), plus label, description, placeholder and unitLabel.

API Reference

Base UI - Number Field