OTP input
OTP input is a neobrutalist React component from Cruise UI. 4 or 6 boxes for a one-time code, with paste, error and a resend countdown. Install it with npx shadcn@latest add @cruiseui/otp-input.
Install
Terminal
npx shadcn@latest add @cruiseui/otp-inputFirst time? Installation shows the one-off components.json setup (the @cruiseui registry) and how to turn the theme on.
Example
Corners
Enter the 6-digit code we sent to 0803 *** 4567
"use client";
import { useState } from "react";
import { CruiseOtpInput } from "@/components/cruise/otp-input";
export default function OtpInputExample() {
const [error, setError] = useState<string>();
return (
<CruiseOtpInput
label="Enter the 6-digit code we sent to 0803 *** 4567"
error={error}
onComplete={(code) => setError(code === "123456" ? undefined : "That code didn't work. Check it and try again.")}
onResend={() => setError(undefined)}
/>
);
}
<p id="otp-label">Enter the 6-digit code we sent to 0803 *** 4567</p>
<div class="otp" role="group" aria-labelledby="otp-label" data-otp>
<input class="otp-box" inputmode="numeric" autocomplete="one-time-code" aria-label="Digit 1 of 6">
<input class="otp-box" inputmode="numeric" autocomplete="off" aria-label="Digit 2 of 6">
<input class="otp-box" inputmode="numeric" autocomplete="off" aria-label="Digit 3 of 6">
<input class="otp-box" inputmode="numeric" autocomplete="off" aria-label="Digit 4 of 6">
<input class="otp-box" inputmode="numeric" autocomplete="off" aria-label="Digit 5 of 6">
<input class="otp-box" inputmode="numeric" autocomplete="off" aria-label="Digit 6 of 6">
</div>
<p class="otp-error" role="alert" hidden>
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" aria-hidden="true"><circle cx="12" cy="12" r="10"/><path d="M12 8v4M12 16h.01"/></svg>
That code didn't work. Check it and try again.
</p>
<button type="button" class="otp-resend" disabled>Resend code in 0:30</button>Needs theme.css. Interactive parts (menus, tabs, drawers) also need the script in the spec for that component.
When to use it
When to use
A code sent by SMS or email to sign in or confirm a payment.
When not to
Passwords or PINs people chose themselves (use an Input).
Props
CruiseOtpInput
| Prop | Type | Default | Description |
|---|---|---|---|
length? | 4 | 6 | 6 | — |
label | string | — | The instruction above the boxes; it labels the group. |
onComplete? | ((code: string) => void) | — | — |
error? | string | — | Shown below the boxes with an icon; turns the borders --danger. |
resendAfter? | number | 30 | Seconds before "Resend code" is enabled; omit onResend to hide it. |
onResend? | (() => void) | — | — |
className? | string | — | — |
Accessibility
- inputmode="numeric" and autocomplete="one-time-code" on the first box, so phones offer the SMS code.
- Each box is labelled "Digit 1 of 6"…; errors are announced with role="alert".