All Taste components
Inputs
OTP input
Six boxes for a one-time code, with paste, backspace and arrow-key support.
filled · focused · empty · resend timer
Enter the 6-digit code
Sent by SMS to +91 98450 •••21
Didn’t get it?
"use client";
import { Fragment, useRef, useState } from "react";
export function OtpInput({ length = 6, label = "One-time code", onComplete }:
{ length?: number; label?: string; onComplete?: (code: string) => void }) {
const [digits, setDigits] = useState<string[]>(() => Array(length).fill(""));
const refs = useRef<(HTMLInputElement | null)[]>([]);
const focus = (i: number) => refs.current[Math.max(0, Math.min(i, length - 1))]?.focus();
function fill(from: number, chars: string) {
const next = [...digits];
chars.split("").forEach((c, k) => { if (from + k < length) next[from + k] = c; });
setDigits(next);
focus(from + chars.length);
if (next.every(Boolean)) onComplete?.(next.join(""));
}
function clear(i: number) {
const next = [...digits];
next[i] = "";
setDigits(next);
}
function onKeyDown(i: number, e: React.KeyboardEvent<HTMLInputElement>) {
if (e.key === "Backspace" && !digits[i] && i > 0) { e.preventDefault(); clear(i - 1); focus(i - 1); }
else if (e.key === "ArrowLeft") { e.preventDefault(); focus(i - 1); }
else if (e.key === "ArrowRight") { e.preventDefault(); focus(i + 1); }
}
return (
<div role="group" aria-label={label} className="flex items-center gap-2">
{digits.map((d, i) => (
<Fragment key={i}>
{i === length / 2 && <span aria-hidden className="h-0.5 w-2 shrink-0 rounded-full bg-border-strong" />}
<input
ref={(el) => { refs.current[i] = el; }}
value={d}
inputMode="numeric"
autoComplete={i === 0 ? "one-time-code" : "off"}
aria-label={"Digit " + (i + 1) + " of " + length}
onFocus={(e) => e.target.select()}
onKeyDown={(e) => onKeyDown(i, e)}
onChange={(e) => {
const v = e.target.value.replace(/\D/g, "");
if (v) fill(i, v.slice(-1)); else clear(i);
}}
onPaste={(e) => {
const v = e.clipboardData.getData("text").replace(/\D/g, "").slice(0, length);
if (v) { e.preventDefault(); fill(0, v); }
}}
className="h-[52px] min-w-0 max-w-11 flex-1 basis-0 rounded border border-border-strong bg-bg text-center text-xl font-medium tabular-nums text-fg caret-primary outline-none transition focus:border-primary focus:ring-[3px] focus:ring-primary/20"
/>
</Fragment>
))}
</div>
);
}
The code uses the Taste Tailwind preset. Make yours on the Taste page with Export my system.