Input OTP
Accessible one-time password component with copy paste functionality.
tsx
import { InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot,} from "@/components/ui/input-otp"
export function InputOTPDemo() { 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
CLI
bash
npx fivui add input-otp
Manual
Install the following dependencies:
bash
npm install input-otp
Copy and paste the following code into your project:
tsx
"use client"
import * as React from "react"import { OTPInput, OTPInputContext } from "input-otp"import { Dot } from "lucide-react"
import { cn } from "@/lib/utils"
const InputOTP = React.forwardRef< React.ElementRef<typeof OTPInput>, React.ComponentPropsWithoutRef<typeof OTPInput>>(({ className, containerClassName, ...props }, ref) => ( <OTPInput ref={ref} containerClassName={cn( "flex items-center gap-2 has-[:disabled]:opacity-50", containerClassName )} className={cn("disabled:cursor-not-allowed", className)} {...props} />))InputOTP.displayName = "InputOTP"
const InputOTPGroup = React.forwardRef< React.ElementRef<"div">, React.ComponentPropsWithoutRef<"div">>(({ className, ...props }, ref) => ( <div ref={ref} className={cn("flex items-center", className)} {...props} />))InputOTPGroup.displayName = "InputOTPGroup"
const InputOTPSlot = React.forwardRef< React.ElementRef<"div">, React.ComponentPropsWithoutRef<"div"> & { index: number }>(({ index, className, ...props }, ref) => { const inputOTPContext = React.useContext(OTPInputContext) const { char, hasFakeCaret, isActive } = inputOTPContext.slots[index]
return ( <div ref={ref} className={cn( "relative flex h-10 w-10 items-center justify-center border-y border-r border-input text-sm transition-all first:rounded-l-md first:border-l last:rounded-r-md", isActive && "z-10 ring-2 ring-ring ring-offset-background", className )} {...props} > {char} {hasFakeCaret && ( <div className="pointer-events-none absolute inset-0 flex items-center justify-center"> <div className="h-4 w-px animate-caret-blink bg-foreground duration-1000" /> </div> )} </div> )})InputOTPSlot.displayName = "InputOTPSlot"
const InputOTPSeparator = React.forwardRef< React.ElementRef<"div">, React.ComponentPropsWithoutRef<"div">>(({ ...props }, ref) => ( <div ref={ref} role="separator" {...props}> <Dot /> </div>))InputOTPSeparator.displayName = "InputOTPSeparator"
export { InputOTP, InputOTPGroup, InputOTPSlot, InputOTPSeparator }
Usage
tsx
import { InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot,} from "@/components/ui/input-otp"
tsx
<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>
Examples
Pattern
Use the pattern
prop to define a custom pattern for the OTP input.
Pattern Validation
Only digits and characters allowed
tsx
"use client"
import { REGEXP_ONLY_DIGITS_AND_CHARS } from "input-otp"
import { InputOTP, InputOTPGroup, InputOTPSlot,} from "@/components/ui/input-otp"
export function InputOTPPattern() { return ( <InputOTP maxLength={6} pattern={REGEXP_ONLY_DIGITS_AND_CHARS}> <InputOTPGroup> <InputOTPSlot index={0} /> <InputOTPSlot index={1} /> <InputOTPSlot index={2} /> <InputOTPSlot index={3} /> <InputOTPSlot index={4} /> <InputOTPSlot index={5} /> </InputOTPGroup> </InputOTP> )}
Separator
You can use the InputOTPSeparator
component to add a separator between the input groups.
With Separators
Multiple separators for better visual grouping
tsx
import { InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot,} from "@/components/ui/input-otp"
export function InputOTPWithSeparator() { 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> )}
Controlled
You can use the value
and onChange
props to control the input value.
Controlled Input
Real-time value display
Enter your one-time password.
tsx
"use client"
import * as React from "react"
import { InputOTP, InputOTPGroup, InputOTPSlot,} from "@/components/ui/input-otp"
export function InputOTPControlled() { const [value, setValue] = React.useState("")
return ( <div className="space-y-2"> <InputOTP maxLength={6} value={value} onChange={(value) => setValue(value)} > <InputOTPGroup> <InputOTPSlot index={0} /> <InputOTPSlot index={1} /> <InputOTPSlot index={2} /> <InputOTPSlot index={3} /> <InputOTPSlot index={4} /> <InputOTPSlot index={5} /> </InputOTPGroup> </InputOTP> <div className="text-center text-sm"> {value === "" ? ( <>Enter your one-time password.</> ) : ( <>You entered: {value}</> )} </div> </div> )}
API Reference
InputOTP
Prop | Type | Default | Description |
---|---|---|---|
maxLength | number | - | The maximum length of the OTP input. |
value | string | - | The controlled value of the OTP input. |
onChange | function | - | Event handler called when the value changes. |
pattern | RegExp | - | Regular expression pattern for input validation. |
disabled | boolean | false | Whether the input is disabled. |
InputOTPSlot
Prop | Type | Default | Description |
---|---|---|---|
index | number | - | The index of the slot in the OTP input. |
External Documentation
Input OTP is built on top of input-otp by @guilherme_rodz. For more advanced usage and API details, refer to the official documentation.
View input-otp Documentation