OTP code input
Six boxes for a verification code that jump forward as you type and back when you delete.
Settings
Code
import { useRef, useState } from "react";
const LENGTH = 6;
interface OtpInputProps {
radius?: number;
value?: string;
onChange?: (value: string) => void;
}
export default function OtpInput({ radius = 12, value, onChange }: OtpInputProps) {
const [internal, setInternal] = useState<string[]>(Array(LENGTH).fill(""));
const refs = useRef<Array<HTMLInputElement | null>>([]);
const digits =
value === undefined
? internal
: Array.from({ length: LENGTH }, (_, i) => value[i] ?? "");
const update = (i: number, x: string) => {
const next = digits.map((d, j) => (j === i ? x : d));
if (value === undefined) setInternal(next);
onChange?.(next.join(""));
};
return (
<div className="flex gap-2">
{digits.map((d, i) => (
<input
key={i}
ref={(el) => {
refs.current[i] = el;
}}
aria-label={`Dígito ${i + 1}`}
value={d}
inputMode="numeric"
maxLength={1}
onChange={(e) => {
const x = e.target.value.replace(/\D/g, "");
update(i, x);
if (x) refs.current[i + 1]?.focus();
}}
onKeyDown={(e) => {
if (e.key === "Backspace" && !d) refs.current[i - 1]?.focus();
}}
className="h-12 w-10 border border-black/10 bg-white text-center text-lg text-[#1d1d1f] outline-none focus:ring-2 focus:ring-[#0071e3] dark:border-white/10 dark:bg-[#1c1c1e] dark:text-[#f5f5f7]"
style={{ borderRadius: radius }}
/>
))}
</div>
);
}
Prompt for AI
Paste it into ChatGPT, Claude or Cursor and it will adapt the block to your project with these settings, even if you don’t use React.
More in Inputs
Where to use it
One-time codes appear in sign-ups, two-factor login, bank transfers and delivery confirmations. Six separate boxes make the code easy to check at a glance, and the cursor moves on its own so people never have to tap each box. It only accepts digits, which is what most OTP input fields in React need.
Many people copy the code from an SMS or email, so consider adding paste support that fills all six boxes at once. Match the corner radius to your other inputs; round boxes look friendly, square ones feel more serious, which may suit a bank better.