A verification screen with single-digit code inputs that auto-advance, accept a pasted code and step back on Backspace, plus a resend countdown, an error shake and a success check.
We sent a 6-digit code to +1 (415) ••• ••92. Change
No signal? Use an authenticator app
npx shadcn@latest add https://hyperblur.dev/r/auth-otp.jsonWorks in any React project set up with the shadcn CLI. The file lands in components/hyperblur/auth-otp.tsx.
import { AuthOtp } from "@/components/hyperblur/auth-otp"
<AuthOtp destination="+1 (415) ••• ••92" onVerify={async (code) => (await fetch("/api/verify", { method: "POST", body: code })).ok} />| Prop | Type | Default | Description |
|---|---|---|---|
| title | string | "Check your phone" | Heading before verification. |
| destination | string | "+1 (415) ••• ••92" | Masked phone number or email the code was sent to. |
| length | number | 6 | Number of digits in the code. |
| defaultValue | string | "" | Digits to prefill, for example from a deep link. |
| resendSeconds | number | 30 | Countdown before the Resend code button becomes available. |
| maxAttempts | number | 5 | Wrong codes allowed before the inputs lock until a new code is requested. |
| onVerify | (code: string) => boolean | void | Promise<boolean | void> | Called when all digits are filled or Verify is pressed. Return or resolve false to reject the code; a rejected promise shows its message. | |
| onResend | () => void | Called when the user requests a new code. | |
| changeHref | string | "#change-number" | Target of the Change link next to the destination. |
| alternate | { label: string; href: string } | null | { label: "Use an authenticator app", href: "#authenticator" } | Fallback method link at the bottom. Pass null to hide it. |
| successCta | { label: string; href: string } | { label: "Continue to Northwind", href: "#continue" } | Button shown after a successful verification. |
| accent | string | "#f5a524" | Rings, focus ring and button color. |