@mshafiqyajid/react-number-input
Headless number input hook and styled component. Decimal, currency, and percent modes via Intl.NumberFormat. Step, min, max, keyboard navigation.
Playground #
Hold +/− to repeat. Shift+arrows or PageUp/PageDown for large step.
Props
TSX
import { NumberInputStyled } from "@mshafiqyajid/react-number-input/styled";
import "@mshafiqyajid/react-number-input/styles.css";
<NumberInputStyled
value={value}
onChange={setValue}
/>Install #
npm install @mshafiqyajid/react-number-input Quick start #
import { NumberInputStyled } from "@mshafiqyajid/react-number-input/styled";
import "@mshafiqyajid/react-number-input/styles.css";
const [price, setPrice] = useState<number | undefined>(0);
<NumberInputStyled
value={price}
onChange={setPrice}
format="currency"
currency="MYR"
min={0}
label="Price"
tone="primary"
/>
// Prefix/suffix
<NumberInputStyled value={weight} onChange={setWeight} suffix="kg" />
<NumberInputStyled value={amount} onChange={setAmount} prefix="RM" /> Scrub mode #
Set scrubable to turn the label into a horizontal drag handle — drag right to increase, left to decrease. The cursor changes to an east-west resize cursor.
<NumberInputStyled
label="Opacity"
value={opacity}
onChange={setOpacity}
min={0}
max={100}
scrubable
scrubPixels={4}
/> Headless #
import { useNumberInput } from "@mshafiqyajid/react-number-input";
const { inputProps, incrementProps, decrementProps } = useNumberInput({
defaultValue: 0,
min: 0,
max: 100,
step: 1,
});
return (
<div className="num">
<button {...decrementProps}>−</button>
<input {...inputProps} />
<button {...incrementProps}>+</button>
</div>
); API #
| Prop | Type | Default | Description |
|---|---|---|---|
| value | number | undefined | — | Controlled value |
| defaultValue | number | — | Uncontrolled initial value |
| onChange | (v: number) => void | — | Called on change |
| min | number | — | Minimum value |
| max | number | — | Maximum value |
| step | number | 1 | Increment step (Arrow keys) |
| bigStep / largeStep | number | step × 10 | Step for Shift+Arrow / PageUp / PageDown (aliases) |
| precision | number | — | Decimal places for display and clamping |
| format | "decimal" | "currency" | "percent" | "decimal" | Display format via Intl.NumberFormat |
| currency | string | — | ISO currency code (required when format="currency") |
| locale | string | "en-US" | Intl locale for formatting |
| label | string | — | Visible label. Also the scrub drag handle when scrubable is set |
| hint | string | — | Helper text below input |
| error | string | — | Error message (overrides hint, sets danger tone) |
| invalid | boolean | false | Force invalid state without inline error text |
| required | boolean | false | Mark field as required |
| size | "sm" | "md" | "lg" | "md" | Input size |
| tone | "neutral" | "primary" | "success" | "danger" | "neutral" | Color tone |
| disabled | boolean | false | Disable interaction |
| readOnly | boolean | false | Read-only mode — value shown but not editable |
| showStepper | boolean | true | Show +/− increment buttons |
| clampOnBlur | boolean | true | Snap to min/max on blur |
| scrubable | boolean | false | Enable drag-to-scrub on the label (drag right = increment, left = decrement) |
| scrubPixels | number | 4 | Pixels of horizontal drag per step when scrubable is true |
| repeat | RepeatOptions | — | Hold-to-repeat configuration: { initialDelay?, interval?, accel? } |
| prefix | string | — | Static text before the value (e.g. "RM") |
| suffix | string | — | Static text after the value (e.g. "kg") |
| placeholder | string | — | Input placeholder |
| onBlur | FocusEventHandler | — | Blur callback |
| onFocus | FocusEventHandler | — | Focus callback |
| name | string | — | Native form name attribute |
| id | string | — | Override the generated input id |
| autoFocus | boolean | — | Auto-focus on mount |
| className | string | — | Extra class on the root element |
| style | CSSProperties | — | Inline style override |
Holding an increment/decrement button auto-repeats (configurable via repeat). Home / End jump to min / max. The stepper animation plays a digit-flip effect in the direction of change.
Edit this page on GitHub