Number Input
Numeric field with parse / clamp, optional percentage suffix, and optional steppers. Composed from Input Group, so it reads identically to every other form field.
<NumberInput defaultValue={1500} prefix="£" />Usage
import { NumberInput } from "@reva/ui";NumberInput owns numeric parsing — value and onValueChange speak number | null (null when the field is empty or not yet a number). It does not wrap a native type="number"; it composes Input Group so the border, hover, focus / invalid rings, radius, and size ladder are identical to Input.
const [amount, setAmount] = useState<number | null>(null);
<NumberInput onValueChange={setAmount} prefix="£" value={amount} />;Type freely — intermediate drafts like - or 1. are preserved while you edit. On blur the value is clamped to min / max and rounded to precision.
Examples
Controlled value
onValueChange fires on every edit and on blur with the parsed number | null.
Value: 1500
"use client";import { NumberInput, Text, VStack } from "@reva/ui";import { useState } from "react";export function AmountField() {const [value, setValue] = useState<number | null>(1500);return ( <VStack className="w-full max-w-xs" gap={2}> <NumberInput aria-label="Amount" onValueChange={setValue} placeholder="0" prefix="£" value={value} /> <Text color="muted-foreground" size="sm"> Value: {value === null ? "null" : value} </Text> </VStack>);}Percentage
Set percent for a trailing % suffix. It is visual only — 3 means 3%, and the value stays 3. Convert to a fraction at your API boundary if the server expects 0.03.
Value: 3.5
<NumberInput max={100} min={0} percent precision={2} value={value} onValueChange={setValue} />Steppers
Set showSteppers for − / + buttons. They (and the Arrow Up / Arrow Down keys) step by step and clamp to min / max.
Value: 2
<NumberInput max={10} min={0} showSteppers step={1} value={value} onValueChange={setValue} />Percentage with steppers
percent and showSteppers compose — the % suffix sits alongside the trailing stepper.
<NumberInput max={100} min={0} percent precision={2} showSteppers step={0.25} value={value} onValueChange={setValue} />Sizes
Set size: sm (32px height), default (40px), lg (44px), xl (48px) — the same ladder as Input.
<VStack className="w-full max-w-sm" gap={3}> <NumberInput defaultValue={42} percent size="sm" /> <NumberInput defaultValue={42} percent size="default" /> <NumberInput defaultValue={42} percent size="lg" /> <NumberInput defaultValue={42} percent size="xl" /></VStack>Disabled
<NumberInput disabled percent value={5} />Invalid
Use aria-invalid for error styling (matches the shared form-control error ring).
<NumberInput aria-invalid percent value={150} />Props
| Prop | Description |
|---|---|
value | Controlled value, number | null. null = empty / not-a-number. |
defaultValue | Uncontrolled initial value, number | null. |
onValueChange | (value: number | null) => void — fires on every edit and on blur. |
min / max | Optional bounds; clamped on blur and on each step. |
step | Increment / decrement for steppers and arrow keys. Default 1. |
precision | Decimal places to round to on blur. |
percent | Render a trailing % suffix (visual only — 3 = 3%). |
showSteppers | Show − / + stepper buttons. |
prefix / suffix | Leading / trailing add-on content (e.g. prefix="£"). percent is sugar for suffix="%". |
size | sm | default | lg | xl — control height, padding, and font size. Default default. |
| … | Other props (name, placeholder, disabled, aria-*, …) forward to the underlying input. |
Native Select
Styled native select element. Lightweight dropdown for short lists, mobile pickers, and forms that benefit from native a11y.
Password strength meter
Presentational four-segment strength indicator with a right-aligned label. Pair with your own password policy or zxcvbn-style scoring in app code.