NumberField
A numeric input built on Base UI’s NumberField primitive. Supports increment/decrement buttons, min/max/step constraints, and scrub-area drag interaction.
Import
import { NumberField } from "chunks-ui";Basic Usage
<NumberField.Root defaultValue={10}>
<NumberField.Group>
<NumberField.Decrement />
<NumberField.Input aria-label="Quantity" />
<NumberField.Increment />
</NumberField.Group>
</NumberField.Root>Min, Max, and Step
Use min and max to constrain the value, and step to set how far the buttons and arrow keys move it. Field.Label names the input:
<Field.Root>
<Field.Label>Quantity (1–20)</Field.Label>
<NumberField.Root defaultValue={5} min={1} max={20}>
<NumberField.Group>
<NumberField.Decrement />
<NumberField.Input />
<NumberField.Increment />
</NumberField.Group>
</NumberField.Root>
</Field.Root>
<Field.Root>
<Field.Label>Step by 5</Field.Label>
<NumberField.Root defaultValue={0} min={0} max={100} step={5}>
<NumberField.Group>
<NumberField.Decrement />
<NumberField.Input />
<NumberField.Increment />
</NumberField.Group>
</NumberField.Root>
</Field.Root>Scrub Area
Wrap a label with NumberField.ScrubArea to allow click-and-drag adjustment. While you drag with a mouse, the browser locks and hides the system pointer. NumberField.ScrubAreaCursor shows in its place, as a left-right arrow by default; pass children or a render element to draw your own. Without ScrubAreaCursor, a mouse scrub shows no pointer at all, so always include it. Safari and touch input keep the system pointer, so the part does not render there:
<NumberField.Root defaultValue={100}>
<NumberField.ScrubArea>
<span>Drag to adjust</span>
<NumberField.ScrubAreaCursor />
</NumberField.ScrubArea>
<NumberField.Group>
<NumberField.Decrement />
<NumberField.Input aria-label="Amount" />
<NumberField.Increment />
</NumberField.Group>
</NumberField.Root>The cursor renders where the popups do: in the PortalContainerProvider’s element, or in the portal of the Dialog, Drawer, Popover, Combobox, Menu, Select or Tooltip it sits in. Its layer is in Z-Index Layers. Like a Dialog, it is placed against the viewport, so a transform or a similar property on the provider’s element or an ancestor offsets it from the pointer: see Container limits.
Disabled
A disabled NumberField is dimmed and shows the not-allowed cursor over its input and buttons.
<NumberField.Root defaultValue={42} disabled>
<NumberField.Group>
<NumberField.Decrement />
<NumberField.Input aria-label="Quantity" />
<NumberField.Increment />
</NumberField.Group>
</NumberField.Root>Mobile Keyboards
Base UI sets inputMode on NumberField.Input for you: numeric, except on iOS, whose number keypad has no minus key. There a min of 0 or more gives the decimal keypad, and without one, or with a negative min, the full keyboard shows, so a minus sign can be typed. Set min={0} when the value can’t be negative, so iOS shows the keypad. An inputMode you pass to NumberField.Input replaces Base UI’s.
A numeric keypad need not have a decimal separator: the HTML spec suggests numeric for PIN entry and asks for the locale’s separator only with decimal. When the value can have a fraction, for example with a fractional step, pass inputMode="decimal" to NumberField.Input. On iOS it also replaces the full keyboard that Base UI shows when min is negative or not set. The decimal keypad has no minus key, so the minus sign can’t be typed on iOS. For a value that can be both negative and fractional, pass inputMode="text": every platform then shows the full keyboard, which Base UI uses on iOS when min is negative or not set.
Text Size
The text of NumberField.Input is 16px below the md breakpoint (768px by default) and on a touch screen, so iOS Safari does not zoom the page when the field takes focus (it zooms into text under 16px); otherwise it is 14px, as in Input. With a mouse, a text-size class on NumberField.Input, such as text-lg, sets the size from md up. A max-md: class, such as max-md:text-lg, sets it below md, on a touch screen too; from md up on a touch screen, a md:[@media(pointer:coarse)]: class sets it. See Text Size in Input for the limits.
Compound Parts
| Part | Description |
|---|---|
NumberField.Root | State container. Manages value, min, max, step, and disabled state. |
NumberField.Group | Wraps Decrement, Input, and Increment into a single bordered control. |
NumberField.Input | The text input. Displays and accepts the numeric value. |
NumberField.Decrement | Button that decrements the value by step. Children you pass replace the minus icon; with a render element and no children, there is no minus icon. The button keeps its aria-label whatever its content: if the children are visible text, pass an aria-label that contains it. |
NumberField.Increment | Button that increments the value by step. Children you pass replace the plus icon; with a render element and no children, there is no plus icon. The button keeps its aria-label whatever its content: if the children are visible text, pass an aria-label that contains it. |
NumberField.ScrubArea | A region the user can click-drag to change the value. |
NumberField.ScrubAreaCursor | The cursor shown in place of the locked system pointer while the user scrubs. Renders a left-right arrow unless you pass children or render. Leave it out and a mouse scrub shows no pointer. |
Props
All parts accept the props from their corresponding Base UI NumberField sub-components. NumberField.Root also takes labels:
Labels
labels replaces the built-in English text, for example to translate it. Keys you leave out keep their default from DEFAULT_NUMBER_FIELD_LABELS. Base UI sets these strings; aria-label on NumberField.Increment or NumberField.Decrement and aria-roledescription on NumberField.Input take precedence. See Labels.