OTP Input

A one-time-code input whose characters roll into place behind a caret that slides from slot to slot.

Dependencies

motion

Interaction Type

Type to fill each slot and move to the next one. Backspace clears a slot in place, then steps back on the next press. Arrow keys move between slots, and a caret slides along with you. Pasting a code, or letting the phone autofill one from a text message, drops it straight in. Set the status to turn the slots green, or shake them red on a wrong code.

Props

Options you can pass to customize this component.

Prop
Type
Description
length
number

How many boxes to render, so a 4 digit code is length={4}. Any count works.

size
smmdlg

Overall scale of the boxes. Maps to 40px (sm), 48px (md), and 56px (lg), and carries the text, caret, and gaps with it.

value
string

The current code. Pass it to control the input yourself; leave it out to let the component track its own state.

defaultValue
string

Starting code when the input is uncontrolled.

onChange
(value: string) => void

Fires on every edit with the full code so far.

onComplete
(value: string) => void

Fires once the last slot is filled.

type
numberslettersboth

Which characters a slot accepts. Anything else is ignored, including on paste.

status
idlesuccesserror

Drives the feedback state. Success traces a green ring around each box in turn, error rings them red and shakes the row once.

mask
boolean

Hides the characters, like a password field.

disabled
boolean

Blocks input and dims every slot.

autoFocus
boolean

Focuses the first slot on mount.

className
string

Extra classes for the row that wraps the slots.

slotClassName
string

Extra classes for each slot, for sizing and colors.

Installation

npx shadcn@latest add swamimalode07/rare-ui/otp-input

How to use

import { useState } from "react"
import OtpInput, { type OtpStatus } from "@/components/ui/otp-input"
export function Demo() {
const [status, setStatus] = useState<OtpStatus>("idle")
return (
<OtpInput
length={6}
size="md"
status={status}
onChange={() => setStatus("idle")}
onComplete={(code) => setStatus(checkCode(code) ? "success" : "error")}
/>
)
}

Source Code

Click the code icon in the top-right corner to view the source code.

Keep in mind

Most components here are recreations of great work from around the web. I don't claim to be the original creator - this is my attempt to reverse-engineer, replicate, and often add a few extra features. I've tried to credit everyone; if I missed someone, let me know.

Contact

Found a bug or issue? Feel free to drop a DM.

License & Usage

  • •MIT with the Commons Clause and an attribution requirement. Free to use, modify and ship in personal and commercial projects, closed source included. You own the code once it is in your project.
  • •Credit is required. Any project shipping a Rare UI component must credit Rare UI with a visible link back to rareui.com, in a footer, an about page, a credits screen or a README.
  • •Don't strip the credit or the copyright notice from the source you copied.
  • •Don't sell, sublicense or redistribute the components themselves, on their own, bundled into a template, kit, theme or paid course, or ported to another framework.
  • •Don't republish them. No mirrors, no re-uploads, no listing them as your own work.
  • •Don't repackage the registry as a competing component library.
  • •Don't claim authorship of a component or of Rare UI itself.
  • •The LICENSE file in the repository is the full text and governs. Ask first if your use doesn't fit these rules.
OTP Input

Enter 123456 to pass. Any other code fails.