InputOTP
A one-time code, typed or pasted into separate slots, with a pattern that refuses the wrong characters.
Input takes a short code, such as the six digits of a verification message, and shows each
character in a slot of its own. Underneath is one real input: typing, deleting, pasting the whole
code and the browser's one-time-code autofill all work as in any text field. It is built on the
input-otp library.
Enter the six digits from the message.
// apps/docs/examples/ui/input-otp.tsx'use client';
import {useState} from 'react';
import { Field, FieldDescription, FieldLabel,} from '@workspace/active-ui/components/primitives/field';import { InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot, REGEXP_ONLY_DIGITS,} from '@workspace/active-ui/components/primitives/input-otp';
/** * A six-digit code in two groups of three. `REGEXP_ONLY_DIGITS` refuses * anything but digits, typed or pasted; `onComplete` fires when the last * slot is filled. The code is checked here against a fixed value: a real * application sends it to its server. */export default function InputOtpExample() { const [code, setCode] = useState(''); const [result, setResult] = useState<'valid' | 'invalid' | null>(null); return ( <Field className="w-fit"> <FieldLabel htmlFor="otp-code">Verification code</FieldLabel> <InputOTP id="otp-code" maxLength={6} pattern={REGEXP_ONLY_DIGITS} value={code} onChange={(value) => { setCode(value); setResult(null); }} onComplete={(value: string) => setResult(value === '123456' ? 'valid' : 'invalid') } aria-describedby="otp-code-status" > <InputOTPGroup> <InputOTPSlot index={0} /> <InputOTPSlot index={1} /> <InputOTPSlot index={2} /> </InputOTPGroup> <InputOTPSeparator /> <InputOTPGroup> <InputOTPSlot index={3} /> <InputOTPSlot index={4} /> <InputOTPSlot index={5} /> </InputOTPGroup> </InputOTP> <FieldDescription id="otp-code-status" aria-live="polite"> {result === 'valid' ? 'Code accepted.' : result === 'invalid' ? 'That code is not valid. Try 123456 in this example.' : 'Enter the six digits from the message.'} </FieldDescription> </Field> );}Usage#
import { InputOTP, InputOTPGroup, InputOTPSlot, REGEXP_ONLY_DIGITS,} from '@workspace/active-ui/components/primitives/input-otp';
<InputOTP maxLength={6} pattern={REGEXP_ONLY_DIGITS} value={code} onChange={setCode}> <InputOTPGroup> <InputOTPSlot index={0} /> {/* … one slot per character, up to index 5 */} </InputOTPGroup></InputOTP>;Anatomy#
Input: the input and its state.OTP maxis the length of the code;Length valueandonmake it controlled;Change onis called with the code when the last character is entered.Complete Input: slots that touch, with joined borders.OTPGroup Input: one character, by itsOTPSlot indexfrom0. It shows the caret when it is the active slot. Render exactlymaxslots.Length Input: a dash between groups,OTPSeparator role="separator".
A pattern that refuses#
pattern is tested against the whole value on every change; a character that does not match is
not accepted. Pass REGEXP_ for a numeric code. Write your own pattern anchored
(^[A-): an unanchored pattern such as [0- matches the empty string and so refuses
nothing.
What your application provides#
A label: an
idonInputwith aOTP Field, orLabel aria-.label The verification.
ononly reports a complete code; checking it is a server matter.Complete Messages for a wrong or expired code, announced with a live region or a
Field.Error
Accessibility and keyboard#
One input:
Tabreaches it once, the arrow keys move within the code,Backspacedeletes.Pasting a whole code fills every slot.
autois set by the library, so phones can offer the code from a message.Complete="one- time- code"
API#
InputOTP
Props
- Type
string
Classes for the element around the slots; class styles the hidden input.
Also takes the props of input-otp, unchanged and documented there: children, max, no, nonce, on, on, paste, push, render, text, value.
Other props, such as the standard attributes of the underlying element, className and ref, are passed through.
InputOTPSlot
Props
- Type
number
The position of the character this slot shows, from 0.
Other props, such as the standard attributes of the underlying element, className and ref, are passed through.
Parts that take only their element’s attributes
Input: the attributes of aOTPGroup <div>, with className and ref.Input: the attributes of aOTPSeparator <div>, with className and ref.
Functions, hooks and constants
- Type
"^\\d+$"
The digit pattern of input- (^\d+$), for pattern on a code field that accepts only digits.
input- tests new Reg. An unanchored pattern such as [0- matches the empty string and so rejects nothing: letters would fill the slots. This constant is anchored and rejects them.
It is exported here so that a code field imports it from this package, not from input-, which is a dependency of this package and not of yours.
This page adapts the Input OTP documentation of shadcn/ui (MIT licence) to this package; see Third-party notices.