Input OTP
A one-time password input with separate slots, a blinking caret and digits that pop into place as you type.
Preview
Usage
import { z } from 'zod'
import { AutoForm } from '@vitnode/core/components/form/auto-form'
import { AutoFormInputOTP } from '@vitnode/core/components/form/fields/input-otp'const formSchema = z.object({
code: z.string().length(6, 'Enter all 6 digits').regex(/^\d+$/, 'Only digits, please'),
})
<AutoForm
formSchema={formSchema}
fields={[
{
id: 'code',
component: props => (
<AutoFormInputOTP
{...props}
description="We sent a 6-digit code to your email."
label="Verify your account"
/>
),
},
]}
/>.length(6) sets the slot count and .regex() becomes the pattern.
One real <input> sits underneath, so paste, password managers and SMS
autofill just work.
Groups and patterns
AutoFormInputOTP halves even codes of 6+ characters and keeps the rest in
one group. Pass groups to choose.
<AutoFormInputOTP {...props} groups={[2, 2, 2]} label="Backup code" />Without a schema, set pattern. Common regexes are re-exported:
import { REGEXP_ONLY_DIGITS } from '@vitnode/core/components/ui/input-otp'<InputOTP maxLength={4} pattern={REGEXP_ONLY_DIGITS}>
…
</InputOTP>REGEXP_ONLY_CHARS and REGEXP_ONLY_DIGITS_AND_CHARS too.
Submit when complete
onComplete fires when every slot is filled, on both components.
<AutoFormInputOTP {...props} onComplete={(code) => verify(code)} />Wrong code
A wrong code comes from your API. setFormFieldError turns every slot red
and shows the message. Try it in the preview.
import { setFormFieldError } from '@vitnode/core/components/ui/form'<AutoForm
formSchema={formSchema}
onSubmit={async (values, form) => {
const res = await verifyCode(values.code)
if (!res.ok) setFormFieldError(form, 'code', "That code doesn't match.")
}}
fields={[...]}
/>Accessibility
AutoFormInputOTPwires the label, description and error to the input.- With
InputOTPalone, add anidand a<Label htmlFor>. Link help text and errors witharia-describedby, and setaria-invalidon errors. - Slots are hidden from screen readers, so no digit is read twice.
- Characters animate in, except with reduced motion.
Props
AutoFormInputOTP takes every InputOTP prop except value and children,
plus:
Prop
Type