react-nat-otp
v1.0.3
Published
Customizable React OTP input with 12 GSAP-powered animations (6 success & 6 error animations).
Maintainers
Readme
react-nat-otp
A modern, accessible React OTP input component powered by 12 GSAP micro-animations (6 celebratory success effects and 6 dynamic error effects).
🌟 Demo & Playground
Experience all animations in action:
- 🎮 Live Interactive Demo: https://react-nat-otp.vercel.app
✨ Features
- 🎭 12 GSAP-Powered Animations: 6 rich success effects and 6 intuitive error feedback animations.
- 🎯 Seamless Verification Flow: Built-in async/sync backend validation with loading state and custom status messages.
- 📱 Robust Input Handling: Smooth single-digit typing, overwrite on focus, backspace navigation, arrow key traversal, and multi-digit paste support.
- 🎨 Deeply Customizable: Control box sizes, gap spacing, corner radius, font sizing, and custom CSS/Tailwind classes.
- 🌐 Framework Agnostic Styles: Works seamlessly with Tailwind CSS or with standard CSS via the included stylesheet.
- ♿ Accessible: Built with keyboard navigation, ARIA attributes, and screen reader announcements.
- 🚀 Production-Ready: Fully typed with TypeScript, delivering lightweight ESM and CommonJS bundles.
📦 Installation
npm install react-nat-otp gsapor with yarn / pnpm / bun:
yarn add react-nat-otp gsap
# or
pnpm add react-nat-otp gsap
# or
bun add react-nat-otp gsapNote: React 18+ is required. Import the stylesheet once in your app entry point (e.g.
main.tsx,App.tsx, orlayout.tsx):
import 'react-nat-otp/styles.css';🚀 Quick Start
'use client';
import React from 'react';
import { OTPInput } from 'react-nat-otp';
import 'react-nat-otp/styles.css';
export default function OtpVerificationPage() {
const verifyOtp = async (code: string) => {
// Simulate real backend API verification
await new Promise((resolve) => setTimeout(resolve, 600));
return code === '12345678';
};
return (
<div style={{ display: 'flex', justifyContent: 'center', padding: '40px' }}>
<OTPInput
length={8}
boxSize={44}
gap={8}
radius={8}
successAnimation="pill"
errorAnimation="shake"
onComplete={(otp) => console.log('OTP entered:', otp)}
onVerify={async (otp) => {
return await verifyOtp(otp);
}}
/>
</div>
);
}🎭 Animations Catalog
🟢 Success Animations (successAnimation)
| Animation | Description |
| :--- | :--- |
| checkmark | Boxes merge into the center and reveal an animated emerald checkmark (✓). |
| pill | Individual boxes smoothly fuse together into a single, cohesive capsule pill button. |
| flip | Staggered 3D domino card flips with elastic bounce settle. |
| burst (Default) | Boxes merge into center with a vibrant 360° multi-colored confetti particle blast. |
| wave | Harmonious liquid sine-wave ripple jump flowing from left to right. |
| jackpot | Casino-style 3D slot machine vertical tumble roll and celebratory glow. |
🔴 Error Animations (errorAnimation)
| Animation | Description |
| :--- | :--- |
| shake (Default) | Boxes converge into center with an animated red cross (✕) and snappy headshake vibration. |
| domino | Domino tile collapse effect that falls outward and rebounds back into place. |
| glitch | Rapid high-frequency crisp haptic vibration with red glow. |
| squash | Bouncy liquid jelly squash-and-stretch drop physics. |
| tornado | 180° alternating cyclone vortex spin from center outward. |
| heartbeat | Urgent double-thump emergency alarm pulse and scale flash. |
⚙️ Props Reference
| Prop | Type | Default | Description |
| :--- | :--- | :--- | :--- |
| length | number | 6 | Total number of OTP digit boxes. |
| boxSize | number | 44 | Box width and height in pixels. |
| gap | number | 8 | Spacing between input boxes in pixels. |
| radius | number | 8 | Corner border radius in pixels. |
| fontSize | number | derived | Custom font size in pixels (defaults to Math.round(boxSize * 0.42)). |
| successAnimation | SuccessAnimationType | 'burst' | 'checkmark' \| 'pill' \| 'flip' \| 'burst' \| 'wave' \| 'jackpot' |
| errorAnimation | ErrorAnimationType | 'shake' | 'shake' \| 'domino' \| 'glitch' \| 'squash' \| 'tornado' \| 'heartbeat' |
| onComplete | (code: string) => void | — | Callback fired synchronously when all digits are entered. |
| onVerify | (code: string) => Promise<boolean \| { success: boolean; message?: string }> | — | Async/sync verification function that communicates with your backend API. |
| autoFocus | boolean | true | Automatically focuses the first input box on component mount. |
| className | string | '' | Custom CSS class names applied to the container. |
| style | React.CSSProperties | — | Custom inline style object applied to the container. |
💡 Advanced Usage
Custom Response Messages from Backend
You can return custom status feedback messages directly from your onVerify function:
<OTPInput
length={6}
onVerify={async (code) => {
const res = await fetch('/api/verify-otp', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ otp: code }),
});
const data = await res.json();
// Return an object with custom status message
return {
success: res.ok && data.success,
message: data.message || (res.ok ? 'Code accepted!' : 'Invalid code!'),
};
}}
/>🛠️ Development & Contributing
To build and test the package locally:
# Clone the repository
git clone https://github.com/betopia/react-nat-otp.git
cd react-nat-otp
# Install dependencies
npm install
# Run type check
npm run typecheck
# Build ESM, CJS, and DTS bundles
npm run build📄 License
MIT © Betopia
