Skip to content

useNumberField

useNumberField takes a state object from useNumberFieldState and returns prop objects (ARIA attributes, event handlers) ready to spread onto your DOM elements.

import { useNumberField } from "raqam";
// or
import { useNumberField } from "raqam/react";
function useNumberField(
props: UseNumberFieldProps,
state: NumberFieldState,
inputRef: React.RefObject<HTMLInputElement>
): NumberFieldAria;

UseNumberFieldProps extends UseNumberFieldStateOptions (all state options are also accepted here for convenience) plus:

PropTypeDescription
idstringExplicit id for the <input>. Auto-generated via useId if omitted.
aria-labelstringAccessible label when no visible label is used.
aria-labelledbystringPoints to an external label element.
aria-describedbystringPoints to a description element.
namestringEnables hiddenInputProps for native form submission.
allowMouseWheelbooleanEnables wheel-based increment/decrement.
copyBehavior"formatted" | "raw" | "number"What goes to the clipboard on Copy/Cut. Default "formatted".

All other props from UseNumberFieldStateOptions (minValue, maxValue, step, formatOptions, etc.) are accepted and forwarded appropriately.

KeySpread ontoDescription
labelProps<label>htmlFor wired to the input id.
groupPropswrapping <div>role="group", aria-disabled.
inputProps<input>Full ARIA spinbutton, keyboard/wheel handlers, cursor logic.
incrementButtonPropsincrement <button>aria-label, disabled, press-and-hold.
decrementButtonPropsdecrement <button>aria-label, disabled, press-and-hold.
hiddenInputProps<input type="hidden">value = the raw number for form submission.
descriptionPropsdescription <p>id for aria-describedby wiring.
errorMessagePropserror <p>role="alert", shown when invalid.
KeyAction
Increment by step
Decrement by step
Shift + ↑/↓Increment/decrement by largeStep
Ctrl/Cmd + ↑/↓Increment/decrement by smallStep
Page UpIncrement by largeStep
Page DownDecrement by largeStep
HomeJump to minValue
EndJump to maxValue
EnterCommit current value
BackspaceSmart deletion (skips over grouping separators)

The returned inputProps also include data-rtl, data-invalid, data-disabled, data-readonly, and data-required attributes so you can style state directly in CSS.

The wheel handler uses a non-passive event listener (bypassing React’s passive-by-default onWheel) so preventDefault() can stop page scroll.

copyBehaviorCopy produces
"formatted" (default)Browser default — the selected text
"raw"String(numberValue) — plain ASCII digits
"number"Alias of "raw"
import { useRef } from "react";
import { useNumberFieldState, useNumberField } from "raqam";
function SpinnerInput({ label }: { label: string }) {
const ref = useRef<HTMLInputElement>(null);
const state = useNumberFieldState({ locale: "en-US", defaultValue: 0 });
const {
labelProps,
groupProps,
inputProps,
incrementButtonProps,
decrementButtonProps,
} = useNumberField({ locale: "en-US" }, state, ref);
return (
<div>
<label {...labelProps}>{label}</label>
<div {...groupProps} style={{ display: "flex" }}>
<button {...decrementButtonProps}></button>
<input {...inputProps} ref={ref} />
<button {...incrementButtonProps}>+</button>
</div>
</div>
);
}