Enter one-time passwords and PINs in segmented fields with paste support. Built on input-otp.
import { InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot,} from "@/components/ui/input-otp"export function Example() { return ( <InputOTP maxLength={6}> <InputOTPGroup> <InputOTPSlot index={0} /> <InputOTPSlot index={1} /> <InputOTPSlot index={2} /> </InputOTPGroup> <InputOTPSeparator /> <InputOTPGroup> <InputOTPSlot index={3} /> <InputOTPSlot index={4} /> <InputOTPSlot index={5} /> </InputOTPGroup> </InputOTP> )}Installation
npx @arctis-sh/@arctis-sh/ui@latest add input-otpUsage
import { InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot,} from "@/components/ui/input-otp"<InputOTP maxLength={6}> <InputOTPGroup> <InputOTPSlot index={0} /> <InputOTPSlot index={1} /> <InputOTPSlot index={2} /> </InputOTPGroup> <InputOTPSeparator /> <InputOTPGroup> <InputOTPSlot index={3} /> <InputOTPSlot index={4} /> <InputOTPSlot index={5} /> </InputOTPGroup></InputOTP>Composition
InputOTP
├── InputOTPGroup
│ ├── InputOTPSlot
│ ├── InputOTPSlot
│ └── InputOTPSlot
├── InputOTPSeparator
└── InputOTPGroup
├── InputOTPSlot
├── InputOTPSlot
└── InputOTPSlotPattern
Use pattern with a helper from input-otp, such as REGEXP_ONLY_DIGITS.
import { REGEXP_ONLY_DIGITS } from "input-otp"import { InputOTP, InputOTPGroup, InputOTPSlot,} from "@/components/ui/input-otp"export function Example() { return ( <InputOTP maxLength={6} pattern={REGEXP_ONLY_DIGITS}> <InputOTPGroup> <InputOTPSlot index={0} /> <InputOTPSlot index={1} /> <InputOTPSlot index={2} /> <InputOTPSlot index={3} /> <InputOTPSlot index={4} /> <InputOTPSlot index={5} /> </InputOTPGroup> </InputOTP> )}Separator
Place InputOTPSeparator between slot groups.
import { InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot,} from "@/components/ui/input-otp"export function Example() { return ( <InputOTP maxLength={6}> <InputOTPGroup> <InputOTPSlot index={0} /> <InputOTPSlot index={1} /> </InputOTPGroup> <InputOTPSeparator /> <InputOTPGroup> <InputOTPSlot index={2} /> <InputOTPSlot index={3} /> </InputOTPGroup> <InputOTPSeparator /> <InputOTPGroup> <InputOTPSlot index={4} /> <InputOTPSlot index={5} /> </InputOTPGroup> </InputOTP> )}Disabled
Set disabled to prevent input.
import { Label } from "@/components/ui/label"import { InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot,} from "@/components/ui/input-otp"export function Example() { return ( <div className="flex flex-col gap-2"> <Label htmlFor="otp-disabled">Verification code</Label> <InputOTP id="otp-disabled" maxLength={6} disabled> <InputOTPGroup> <InputOTPSlot index={0} /> <InputOTPSlot index={1} /> <InputOTPSlot index={2} /> </InputOTPGroup> <InputOTPSeparator /> <InputOTPGroup> <InputOTPSlot index={3} /> <InputOTPSlot index={4} /> <InputOTPSlot index={5} /> </InputOTPGroup> </InputOTP> </div> )}Controlled
Control the value with value and onChange.
"use client"import * as React from "react"import { Label } from "@/components/ui/label"import { InputOTP, InputOTPGroup, InputOTPSlot,} from "@/components/ui/input-otp"export function Example() { const [value, setValue] = React.useState("") return ( <div className="flex flex-col items-center gap-2"> <Label htmlFor="otp-controlled">Enter your one-time password.</Label> <InputOTP id="otp-controlled" maxLength={6} value={value} onChange={setValue} > <InputOTPGroup> <InputOTPSlot index={0} /> <InputOTPSlot index={1} /> <InputOTPSlot index={2} /> <InputOTPSlot index={3} /> <InputOTPSlot index={4} /> <InputOTPSlot index={5} /> </InputOTPGroup> </InputOTP> <div className="text-sm tracking-wide text-muted-foreground"> {value === "" ? "Enter your one-time password." : `You entered: ${value}`} </div> </div> )}Invalid
Set aria-invalid on slots for an error state.
"use client"import * as React from "react"import { InputOTP, InputOTPGroup, InputOTPSlot,} from "@/components/ui/input-otp"export function Example() { const [value, setValue] = React.useState("000000") return ( <InputOTP maxLength={6} value={value} onChange={setValue}> <InputOTPGroup> <InputOTPSlot index={0} aria-invalid /> <InputOTPSlot index={1} aria-invalid /> <InputOTPSlot index={2} aria-invalid /> <InputOTPSlot index={3} aria-invalid /> <InputOTPSlot index={4} aria-invalid /> <InputOTPSlot index={5} aria-invalid /> </InputOTPGroup> </InputOTP> )}Four Digits
Create a four-digit PIN field with maxLength={4} and REGEXP_ONLY_DIGITS.
import { REGEXP_ONLY_DIGITS } from "input-otp"import { InputOTP, InputOTPGroup, InputOTPSlot,} from "@/components/ui/input-otp"export function Example() { return ( <InputOTP maxLength={4} pattern={REGEXP_ONLY_DIGITS}> <InputOTPGroup> <InputOTPSlot index={0} /> <InputOTPSlot index={1} /> <InputOTPSlot index={2} /> <InputOTPSlot index={3} /> </InputOTPGroup> </InputOTP> )}Alphanumeric
REGEXP_ONLY_DIGITS_AND_CHARS accepts letters and numbers. Set inputMode="text" to show the full keyboard on mobile; the library defaults to numeric.
import { REGEXP_ONLY_DIGITS_AND_CHARS } from "input-otp"import { InputOTP, InputOTPGroup, InputOTPSlot,} from "@/components/ui/input-otp"export function Example() { return ( <InputOTP maxLength={6} pattern={REGEXP_ONLY_DIGITS_AND_CHARS} inputMode="text" > <InputOTPGroup> <InputOTPSlot index={0} /> <InputOTPSlot index={1} /> <InputOTPSlot index={2} /> <InputOTPSlot index={3} /> <InputOTPSlot index={4} /> <InputOTPSlot index={5} /> </InputOTPGroup> </InputOTP> )}API Reference
See the input-otp documentation for the full set of root props, including maxLength, pattern, value, onChange, and onComplete.
InputOTP
| Prop | Type | Default |
|---|---|---|
| maxLength | number | — |
| pattern | string | — |
| value | string | — |
| onChange | (value: string) => void | — |
| disabled | boolean | — |
| containerClassName | string | — |
| className | string | — |
<InputOTP maxLength={6}> <InputOTPGroup> <InputOTPSlot index={0} /> <InputOTPSlot index={1} /> <InputOTPSlot index={2} /> </InputOTPGroup></InputOTP>InputOTPSlot
| Prop | Type | Default |
|---|---|---|
| index | number | — |
| className | string | — |
Native div attributes, including aria-invalid, are supported.
<InputOTPSlot index={0} />InputOTPGroup
<InputOTPGroup> <InputOTPSlot index={0} /></InputOTPGroup>InputOTPSeparator
<InputOTPSeparator />