Underlined OTP Input
A sleek, minimalist bottom-border verification input featuring an expanding focus accent line, sliding character spring physics, and mobile SMS authentication styling.
SMS Authentication
Enter your code or test with
Component Overview & Selection Guide
Use the Underlined OTP Input for mobile-first auth flows, lightweight SMS OTP verification screens, and minimalist web applications that favor understated, modern line aesthetics.
Primary Use Cases:
- Mobile SMS Verification: Minimalist phone number verification cards with crisp typography.
- Minimal Auth Modals: Lightweight slide-over panels or dialogs where borderless inputs reduce visual clutter.
- Quick 4 or 6-Digit Passcodes: Streamlined authentication screens.
Features
- Expanding Accent Underline: Floating focus underline smoothly stretches under the active digit slot.
- Subtle Drop Physics: Numbers slide into place from above with spring physics.
- Dynamic Colored Underlines: Instantly turns red on error or emerald green on completion.
- Mobile Autofill Ready: Fully compatible with mobile SMS verification code auto-detection.
Installation
bunx shadcn@latest add https://jackui.com/r/underlined-otp-input.jsonnpx shadcn@latest add https://jackui.com/r/underlined-otp-input.jsonpnpm dlx shadcn@latest add https://jackui.com/r/underlined-otp-input.jsonThe CLI will automatically install the motion and lucide-react dependencies and copy the component into your project at:
components/jackui/otp-input/underlined-otp-input.tsxUsage
"use client";
import React, { useState } from "react";
import { UnderlinedOtpInput } from "@/components/jackui/otp-input/underlined-otp-input";
export default function UnderlinedOtpVerification() {
const [code, setCode] = useState("");
const [isError, setIsError] = useState(false);
const [isSuccess, setIsSuccess] = useState(false);
return (
<div className="flex flex-col items-center justify-center p-8">
<UnderlinedOtpInput
length={6}
value={code}
onChange={setCode}
onComplete={(val) => {
if (val === "789012") setIsSuccess(true);
else setIsError(true);
}}
isError={isError}
isSuccess={isSuccess}
autoFocus
/>
</div>
);
}Props
| Prop | Type | Description |
|---|---|---|
length | number | Optional. Total number of digit slots (typically 4, 6, or 8). Default: 6 |
value | string | Optional. Controlled input value string. |
onChange | (value: string) => void | Optional. Callback fired on input value change. |
onComplete | (value: string) => void | Optional. Callback fired when all slots are filled. |
type | "number" | "text" | "password" | Optional. Input character filter type. Default: "number" |
mask | boolean | Optional. Whether to mask characters with bullet dots. Default: false |
disabled | boolean | Optional. Disables input interaction and dims slots. Default: false |
autoFocus | boolean | Optional. Automatically focuses the first slot on mount. Default: false |
isError | boolean | Optional. Displays error state with shake physics and red underline. Default: false |
isSuccess | boolean | Optional. Displays emerald success underline feedback. Default: false |
size | "sm" | "md" | "lg" | Optional. Size scale of the input slots. Default: "md" |
placeholder | string | Optional. Character placeholder for empty slots. Default: "" |
className | string | Optional. Additional outer container CSS class names. |
slotClassName | string | Optional. Additional individual slot CSS class names. |
ref | React.Ref<UnderlinedOtpInputRef> | Optional. Imperative ref handle exposing focus(), blur(), and clear() methods. |
Classic OTP Input
A crisp, modern bordered verification input featuring spring-animated character drops, dynamic active slot glow tracking, masking toggle, and built-in error shake physics.
Filled OTP Input
A soft-tinted, elevated tactile tile input designed for modern Fintech banking, transaction approvals, and high-security PIN entry.
