@mshafiqyajid/react-otp-input
Headless OTP / verification-code input hook and styled component for React. Smart paste fills all slots. Full keyboard nav. Masking, group separators, label/hint/error states, and SMS autofill via autoComplete=one-time-code.
Playground #
Verification code
Type or paste to auto-fill
Props
TSX
import { OTPInputStyled } from "@mshafiqyajid/react-otp-input/styled";
import "@mshafiqyajid/react-otp-input/styles.css";
<OTPInputStyled
onComplete={handleComplete}
/>Install #
npm install @mshafiqyajid/react-otp-input Quick start #
import { OTPInputStyled } from "@mshafiqyajid/react-otp-input/styled";
import "@mshafiqyajid/react-otp-input/styles.css";
<OTPInputStyled
length={6}
tone="primary"
onComplete={(code) => verify(code)}
autoFocus
/> Recipes #
Controlled with verification flow
const [code, setCode] = useState("");
const [status, setStatus] = useState<"idle" | "verifying" | "error">("idle");
<OTPInputStyled
length={6}
value={code}
onChange={(v) => { setCode(v); setStatus("idle"); }}
onComplete={async (final) => {
setStatus("verifying");
try { await verify(final); } catch { setStatus("error"); }
}}
error={status === "error" ? "Invalid code" : undefined}
disabled={status === "verifying"}
/> Alphanumeric pattern (e.g. license keys)
<OTPInputStyled
length={8}
pattern="alphanumeric"
groupSize={4}
uppercase
label="License key"
/> Masked PIN entry
<OTPInputStyled
length={4}
mask
pattern="numeric"
label="PIN"
hint="Hidden for privacy"
/> API #
OTPInputStyled
| Prop | Type | Default | Description |
|---|---|---|---|
| length | number | 6 | Number of slots. |
| value | string | — | Controlled value. |
| onChange | (value: string) => void | — | Fires on change. |
| onComplete | (value: string) => void | — | Fires when all slots filled. |
| pattern | numeric | alphanumeric | any | RegExp | fn | numeric | Allowed characters. |
| variant | solid | outline | underline | solid | Visual style. |
| size | sm | md | lg | md | Size. |
| tone | neutral | primary | success | danger | neutral | Color theme. |
| mask | boolean | false | Show maskChar instead of typed char. |
| groupSize | number | — | Insert separator after every N slots. |
| autoFocus | boolean | false | Focus first slot on mount. |
| label | ReactNode | — | Label above. |
| hint | ReactNode | — | Helper text below. |
| error | ReactNode | — | Error text — flips tone to danger. |