Input OTP
A one-time-code field: six boxes, one digit each. Looks like six inputs and behaves like one value - typing advances, Backspace steps back, arrows move without editing, and a pasted or autofilled code spreads itself across the boxes.
Installation
You can add this OTP input using our CLI or manually:
Dark mode ready - this component follows BoardUI semantic tokens automatically. Set up theme switching.
The CLI copies the component source (with its internal dependencies) into your project and installs any required npm packages.
npx boardui@latest add input-otpControlled value
The value is a single string, not an array of characters. Pass value + onChange to control it, or defaultValue to leave it uncontrolled. onComplete fires the moment the last box fills, which is usually where you submit.
const [code, setCode] = useState("");
<InputOtp value={code} onChange={setCode} onComplete={(value) => verify(value)} aria-label="Verification code"/>Length, grouping and states
length sets the number of boxes and groupEvery splits them into runs, which makes a long code easier to read back. isInvalid gives the boxes a red edge over the same tint a failed Input uses.
{/* Four boxes instead of six */}<InputOtp length={4} aria-label="PIN" />
{/* Split into groups: 000 000 */}<InputOtp groupEvery={3} aria-label="Verification code" />
{/* States */}<InputOtp isInvalid aria-label="Verification code" /><InputOtp isDisabled defaultValue="1234" aria-label="Verification code" />Paste and autofill
Pasting into any box distributes the digits from that point onward rather than dropping everything but the first character. The same path handles OS autofill: iOS and Chrome deliver the whole code into a single box, so each box carries autoComplete="one-time-code" and accepts more than one character. Non-digits are stripped throughout, and the boxes use inputMode="numeric" so phones show a number pad without the spinners and stray characters a number input would bring.