Skip to content

NumberField Components

The NumberField namespace exports headless compound components that handle all wiring internally via React Context. No prop drilling, no ref management.

import { NumberField } from "raqam";
<NumberField.Root ...> {/* context provider + state */}
<NumberField.Label /> {/* <label> */}
<NumberField.Group> {/* <div role="group"> */}
<NumberField.Decrement /> {/* <button> */}
<NumberField.Input /> {/* <input type="text"> */}
<NumberField.Increment /> {/* <button> */}
</NumberField.Group>
<NumberField.ScrubArea> {/* drag-to-change wrapper */}
<NumberField.ScrubAreaCursor /> {/* custom pointer cursor */}
</NumberField.ScrubArea>
<NumberField.Formatted /> {/* read-only formatted display */}
<NumberField.Description /> {/* helper text */}
<NumberField.ErrorMessage /> {/* validation error */}
<NumberField.HiddenInput /> {/* form submission value */}
</NumberField.Root>

Only Root and Input are required. All others are optional.


Context provider. Accepts all UseNumberFieldStateOptions props plus:

PropTypeDescription
localestringBCP 47 locale. Defaults to the current runtime locale.
formatOptionsIntl.NumberFormatOptionsNumber format configuration.
value / defaultValuenumber | nullControlled/uncontrolled value.
onChange(v: number | null) => voidCalled whenever the parsed numeric value changes.
onValueChange(v, details) => voidLike onChange, plus { reason, formattedValue }.
minValue / maxValuenumberConstraints.
step / largeStep / smallStepnumberStep sizes.
validate(v: number | null) => boolean | stringCustom validator.
disabled / readOnlybooleanInteraction state.
requiredbooleanMarks the field as required.
allowNegative / allowDecimalbooleanInput constraints.
prefix / suffixstringAffixes.
namestringGenerates hidden input props for native form submission.
allowMouseWheelbooleanEnable wheel-based increment/decrement.
copyBehavior"formatted" | "raw" | "number"Clipboard behaviour.
allowOutOfRangebooleanSkip clamping; show aria-invalid instead.

Data attributes set on the root element:

AttributeSet when
data-focusedInput is focused
data-invalidValue is invalid
data-disableddisabled is true
data-readonlyreadOnly is true
data-requiredrequired is true
data-scrubbingA scrub interaction is active

If you only care about commit-time analytics, use onValueChange and check the reason field ("blur", "keyboard", "increment", "decrement", "wheel", "paste", "input", "clear", or "scrub").


The text input. Accepts all standard <input> props except type (always "text").

PropTypeDescription
renderRenderProp<"input">Swap the element (e.g. a styled component).

<NumberField.Label>Price</NumberField.Label>

Renders a <label> with htmlFor wired to the input id. Accepts all <label> props.


Wraps the input and stepper buttons. Renders <div role="group">. Accepts all <div> props.


Stepper buttons. Accepts all <button> props.

<NumberField.Decrement>−</NumberField.Decrement>
<NumberField.Increment>+</NumberField.Increment>

Buttons are automatically disabled when at minValue/maxValue or when the field is disabled or readOnly.

Press-and-hold acceleration: hold for stepHoldDelay ms → interval fires at stepHoldInterval ms.


Wraps any element; dragging over it adjusts the value via Pointer Lock API.

PropTypeDefaultDescription
direction"horizontal" | "vertical" | "both""horizontal"Drag axis.
pixelSensitivitynumber4Pixels dragged per step.
renderRenderProp—Custom element.
<NumberField.ScrubArea direction="horizontal" pixelSensitivity={2}>
Drag to adjust
</NumberField.ScrubArea>

data-scrubbing is set on the element while dragging.


Optional. Renders only while scrubbing so you can show custom visual feedback next to the active scrub handle. Accepts <span> props.

<NumberField.ScrubArea>
<span>Drag me</span>
<NumberField.ScrubAreaCursor>
↔
</NumberField.ScrubAreaCursor>
</NumberField.ScrubArea>

A <span> (or custom element) that displays the current formatted value as read-only text. Useful for dual-display UIs (edit + display side by side).

<NumberField.Formatted />
{/* Renders: "$1,234.56" */}

Helper text. Automatically wired to aria-describedby on the input.

<NumberField.Description>
Enter a value between 0 and 100.
</NumberField.Description>

Displays validation errors. Has role="alert" and is only shown when the field is invalid.

If you pass no children, it renders state.validationError automatically:

<NumberField.ErrorMessage />
{/* Renders: "Must be a positive number" */}

Or supply your own content:

<NumberField.ErrorMessage>
Custom error text.
</NumberField.ErrorMessage>

An <input type="hidden"> for HTML form submission. Its value is always the raw number (no formatting). To enable it, pass name to NumberField.Root.

<NumberField.Root locale="en-US" name="price">
<NumberField.Input />
<NumberField.HiddenInput />
</NumberField.Root>

The visual building blocks (Label, Group, Input, Increment, Decrement, ScrubArea, ScrubAreaCursor, and Formatted) accept a render prop for element replacement (no asChild peer deps required):

<NumberField.Input
render={(props) => <MyStyledInput {...props} />}
/>