Developer Docs
Quick reference guides with props tables, usage examples, and best practices for rapid development
OTPInput
One-time password input with auto-focus progression and paste support
OTPInput
A one-time password input component with intelligent navigation and paste support. Creates individual inputs for each digit with automatic focus management, auto-advance, backspace navigation, and clipboard integration.
Live Example
Current value: [object Object]🔧 Props
| Prop | Type | Default | Description |
|---|---|---|---|
| value | van.State | van.state('') | OTP value state (automatically updated) |
| length | number | 6 | Number of OTP digits (4-8 typical) |
| autofocus | boolean | false | Auto-focus first input on mount (100ms setTimeout) |
| onComplete | Function | undefined | Callback when all digits entered (receives complete code) |
| disabled | boolean | State | false | Whether inputs are disabled |
| class | string | '' | Input classes (overrides defaults via filterClassName) |
| containerClass | string | '' | Container wrapper classes (flex gap-2 justify-center) |
| id | string | auto | Container ID (auto-generated: input-{timestamp}) |
💻 Basic Usage
Default 6-digit OTP with auto-focus and completion callback.
const otp = van.state('');
OTPInput({
value: otp,
autofocus: true,
onComplete: (code) => {
console.log('OTP entered:', code);
verifyOTP(code);
}
})📏 Custom Length
4-digit PIN or 8-digit code - any length supported.
4-Digit PIN
const pin = van.state('');
OTPInput({
length: 4,
value: pin,
onComplete: (code) => validatePIN(code)
})8-Digit Code
OTPInput({
length: 8,
value: code,
class: 'size-8 text-base' // Smaller inputs for 8 digits
})🎨 Custom Styling
Override input appearance and container spacing with Tailwind classes.
Large Inputs
OTPInput({
value: otp,
class: 'size-12 text-2xl rounded-xl border-4 border-sky',
containerClass: 'gap-4' // More spacing between inputs
})Custom Colors
OTPInput({
value: otp,
class: 'size-10 text-xl bg-white border-2 border-sunset focus:border-sunrise focus:ring-2 focus:ring-sunrise/20'
})🚫 Disabled State
Show OTP inputs in disabled state (e.g., during verification).
const verifying = van.state(false);
OTPInput({
value: otp,
disabled: verifying // Disable during API call
})⌨️ Smart Navigation
Built-in keyboard navigation for seamless user experience.
✅Auto-advance on digit entry
Automatically moves to next input when a digit is entered
✅Backspace navigation
Pressing backspace on empty input moves to previous input
✅Arrow key navigation
Use left/right arrow keys to move between inputs
✅Auto-select on focus
Clicking an input automatically selects its content for easy replacement
🕐 Paste Support
Intelligent clipboard integration with automatic digit distribution.
✅Numeric filtering
Pasted content is automatically filtered to only include digits (0-9)
✅Auto-distribution
Pasted digits are automatically distributed across inputs from paste position
✅Length limiting
Pasted content is truncated to fit remaining inputs (e.g., paste "123456789" into 6-digit OTP)
✅Focus management
Focus automatically moves to last filled input after paste
// User pastes "123456789" into first input of 6-digit OTP
// Result: Inputs show "1 2 3 4 5 6", extra digits ignored
// Focus moves to 6th input automatically⚡️ Best Practices
✓ Do This
✓Use autofocus for better UX
- Set autofocus: true so users can immediately start typing without clicking.
✓Provide onComplete callback
- Auto-submit verification when all digits are entered for faster flow.
✓Use appropriate length
- Common lengths: 4 (PIN), 6 (OTP), 8 (security codes). Match your backend requirements.
✓Disable during verification
- Set disabled: true while verifying to prevent re-submission and changes.
✓Clear on error
- Reset value to empty string when verification fails for better UX.
✗ Avoid This
✗Don't use very small inputs
- Minimum size-8 recommended for mobile touch targets (44x44px accessibility guideline).
✗Don't forget to handle paste
- Paste support is built-in, but make sure your onComplete handler can process pasted codes.
✗Don't use extreme lengths
- Stick to 4-8 digits. Longer codes should use a single input field instead.
✨ Key Features
⭑Individual State Per Input
- Dual-state pattern: each input has its own state, plus parent state for the complete value.
⭑Auto-Updated Parent State
- Parent state automatically updates as a concatenated string of all digit values.
⭑Smart Navigation
- Auto-advance on input, backspace to previous, arrow key navigation between inputs.
⭑Paste Support
- Built-in paste handling with numeric filtering - extracts only digits from pasted content.
⭑Auto-Focus
- First input auto-focuses with 100ms setTimeout to ensure DOM readiness.
⭑onComplete Callback
- Fires once when all digits are entered, perfect for auto-submit verification.
⭑Numeric-Only Input
- Enforces numeric input with special key allowances (backspace, delete, arrows, tab).
⭑Auto-Select on Focus
- Existing digit auto-selects on focus for easy replacement without backspace.
⭑Disabled State Support
- All inputs disable together, useful during verification process.
⭑Full Tailwind Override
- filterClassName enables complete styling customization with any Tailwind classes.
⭑Auto-Generated IDs
- Automatic unique ID generation if not provided, preventing console errors.
⭑DOM Leakage Prevention
- Proper cleanup of event listeners and timeouts to prevent memory leaks.
Explore More Components
Browse other component categories