Skip to content

useNumberFieldState

useNumberFieldState manages all state for a number field: the formatted display string, the underlying numeric value, validation, focus, and scrubbing.

Pair it with useNumberField to get ARIA prop objects for your elements.

import { useNumberFieldState } from "raqam";
// or
import { useNumberFieldState } from "raqam/react";
function useNumberFieldState(
options: UseNumberFieldStateOptions
): NumberFieldState;
PropTypeDefaultDescription
localestringruntime defaultBCP 47 locale tag. Drives Intl.NumberFormat.
formatOptionsIntl.NumberFormatOptions{}Passed to Intl.NumberFormat.
valuenumber | nullControlled value.
defaultValuenumber | nullnullUncontrolled initial value.
onChange(value: number | null) => voidCalled whenever the parsed numeric value changes.
PropTypeDefaultDescription
minValuenumberMinimum allowed value.
maxValuenumberMaximum allowed value.
stepnumber1Normal step (↑/↓ arrow keys).
largeStepnumber10Large step (Shift+↑/↓, Page Up/Down).
smallStepnumber0.1Small step (Ctrl/Cmd+↑/↓).
clampBehavior"blur" | "strict" | "none""blur"When to clamp to min/max.
allowOutOfRangebooleanfalseSkip clamping; sets aria-invalid when out of range.
allowNegativebooleantrueAllow negative values.
allowDecimalbooleantrueAllow decimal input.
PropTypeDefaultDescription
maximumFractionDigitsnumberOverride formatOptions.maximumFractionDigits.
minimumFractionDigitsnumberOverride formatOptions.minimumFractionDigits.
fixedDecimalScalebooleanfalseAlways show maximumFractionDigits decimal places.
prefixstringPrepend a string (e.g. "$").
suffixstringAppend a string (e.g. " kg").
liveFormatbooleantrueFormat on every keystroke (disable for IME locales).
PropTypeDefaultDescription
validate(v: number | null) => boolean | string | nullCustom validator. Return true for valid, string for error message.
PropTypeDefaultDescription
formatValue(v: number) => stringReplace the default formatter.
parseValue(s: string) => { value: number | null; isIntermediate: boolean }Replace the default parser.
onRawChange(raw: string | null) => voidCalled with the exact string the user typed (for arbitrary precision).
PropTypeDefaultDescription
stepHoldDelaynumber400Milliseconds before press-and-hold acceleration starts.
stepHoldIntervalnumber200Milliseconds between accelerated steps.
disabledbooleanfalseDisable all interaction.
readOnlybooleanfalseAllow focus, disallow editing.
PropertyTypeDescription
inputValuestringThe formatted string currently shown in the input.
numberValuenumber | nullThe parsed numeric value (null when empty/invalid).
rawValuestring | nullThe exact string the user typed (for precision use cases).
isFocusedbooleanWhether the input is focused.
isScrubbingbooleanWhether a scrub drag is in progress.
canIncrementbooleanFalse when at maxValue or disabled.
canDecrementbooleanFalse when at minValue or disabled.
validationState"valid" | "invalid"Result of the validate callback plus range checks.
validationErrorstring | nullError message from validate, or null.
increment()() => voidStep up by step.
decrement()() => voidStep down by step.
incrementToMax()() => voidJump to maxValue.
decrementToMin()() => voidJump to minValue.
setInputValue(s)(s: string) => voidDirectly set the display string.
setNumberValue(n)(n: number | null) => voidDirectly set the numeric value.
commit()() => voidTrigger blur-time formatting and clamping.
setIsFocused(b)(b: boolean) => voidSync focus state (called by useNumberField).
setIsScrubbing(b)(b: boolean) => voidSync scrub state (called by useScrubArea).
import { useRef } from "react";
import { useNumberFieldState, useNumberField } from "raqam";
function MyInput() {
const ref = useRef<HTMLInputElement>(null);
const state = useNumberFieldState({
locale: "en-US",
formatOptions: { style: "currency", currency: "USD" },
minValue: 0,
onChange: (value) => console.log("parsed value:", value),
});
const { labelProps, inputProps } = useNumberField(
{ locale: "en-US", formatOptions: { style: "currency", currency: "USD" } },
state,
ref,
);
return (
<>
<label {...labelProps}>Amount</label>
<input {...inputProps} ref={ref} />
<p>Current: {state.numberValue}</p>
</>
);
}

If you need change metadata such as "increment" vs "paste" vs "blur", use NumberField.Root with onValueChange instead of the raw state hook.