OTP Code Form (Component)
Description
The OTPCodeForm component is a modern, accessible form for entering One-Time Password (OTP) codes. It provides a smooth user experience with auto-focus, paste support, and visual feedback.
Preview
*Modern OTP input form with individual digit inputs and validation states*Features
- 🔢 Individual digit inputs with auto-focus navigation
- 📋 Paste support for quick code entry
- ⌨️ Keyboard navigation (arrows, backspace, enter)
- ✅ Visual feedback (error, success, loading states)
- 🔄 Auto-submit when code is complete
- 📱 Responsive design with mobile optimization
- ♿ Accessibility with ARIA labels and keyboard support
Usage
Basic Usage
vue
<template>
<OtpCodeForm
type="sms"
title="Check your phone"
description="Code sent to your phone"
/>
</template>
<script setup>
const handleOTPSubmit = (code) => {
console.log('OTP Code:', code)
// Verify the code
}
const handleResend = () => {
console.log('Resend OTP')
// Send new OTP
}
</script>With Custom Configuration
vue
<template>
<OTPCodeForm
:length="4"
title="Enter 4-digit code"
description="Check your SMS for the verification code"
:auto-submit="false"
:loading="isVerifying"
:error-message="errorMessage"
:resend-cooldown="resendTimer"
@submit="verifyCode"
:type="sms"
@resend="sendNewCode"
/>
</template>
<script setup>
const isVerifying = ref(false)
const errorMessage = ref('')
const resendTimer = ref(0)
const verifyCode = async (code) => {
isVerifying.value = true
try {
await verifyOTPCode(code)
} catch (error) {
errorMessage.value = 'Invalid code. Please try again.'
} finally {
isVerifying.value = false
}
}
const sendNewCode = async () => {
resendTimer.value = 60
// Start countdown
const interval = setInterval(() => {
resendTimer.value--
if (resendTimer.value <= 0) {
clearInterval(interval)
}
}, 1000)
// Send new code
await sendOTPCode()
}
</script>Props
| Prop | Type | Default | Description |
|---|---|---|---|
title | string | 'Enter Verification Code' | Form title |
description | string | 'We sent a 6-digit code to your email' | Form description |
submitText | string | 'Verify Code' | Submit button text |
loadingText | string | 'Verifying...' | Loading button text |
resendText | string | 'Resend Code' | Resend button text |
length | number | 6 | Number of OTP digits |
autoSubmit | boolean | true | Auto-submit when complete |
loading | boolean | false | Loading state |
errorMessage | string | '' | Error message to display |
resendCooldown | number | 0 | Resend cooldown in seconds |
type | string | Choose between SMS or EMAIL to switch Icons |
Events
| Event | Payload | Description |
|---|---|---|
submit | code: string | Emitted when form is submitted |
resend | - | Emitted when resend button is clicked |
complete | code: string | Emitted when code is complete |
change | code: string | Emitted on any input change |
Examples
Email Verification
vue
<template>
<OTPCodeForm
title="Verify your email"
description="Enter the 6-digit code sent to your email"
@submit="verifyEmail"
@resend="resendEmailCode"
/>
</template>
<script setup>
const verifyEmail = async (code) => {
const { error } = await supabase.auth.verifyOtp({
token: code,
type: 'email'
})
if (error) {
// Handle error
} else {
// Email verified
await navigateTo('/dashboard')
}
}
const resendEmailCode = async () => {
await supabase.auth.resend({
type: 'signup',
email: userEmail.value
})
}
</script>Phone Verification
vue
<template>
<OTPCodeForm
:length="4"
title="Verify your phone"
description="Enter the 4-digit code sent via SMS"
:resend-cooldown="resendCooldown"
@submit="verifyPhone"
@resend="resendSMSCode"
/>
</template>
<script setup>
const resendCooldown = ref(0)
const verifyPhone = async (code) => {
// Verify SMS code
const isValid = await verifySMSCode(code)
if (isValid) {
// Phone verified
}
}
const resendSMSCode = async () => {
resendCooldown.value = 60
// Start countdown
const timer = setInterval(() => {
resendCooldown.value--
if (resendCooldown.value <= 0) {
clearInterval(timer)
}
}, 1000)
// Send SMS
await sendSMSCode()
}
</script>Two-Factor Authentication
vue
<template>
<OTPCodeForm
title="Two-Factor Authentication"
description="Enter your authenticator app code"
:auto-submit="false"
@submit="verify2FA"
/>
</template>
<script setup>
const verify2FA = async (code) => {
const isValid = await verifyTOTPCode(code)
if (isValid) {
// 2FA successful
await navigateTo('/dashboard')
} else {
// Show error
}
}
</script>Styling
The component uses Tailwind CSS classes and supports dark mode:
Custom Styling
vue
<template>
<OTPCodeForm
class="custom-otp-form"
@submit="handleSubmit"
/>
</template>
<style>
.custom-otp-form .otp-input {
border-color: #your-color;
}
.custom-otp-form .submit-button {
background-color: #your-primary-color;
}
</style>Accessibility
- ARIA labels for screen readers
- Keyboard navigation support
- Focus management with auto-focus
- Error announcements for validation
- High contrast support in dark mode
Best Practices
- Always provide clear instructions in the description
- Handle errors gracefully with user-friendly messages
- Implement resend cooldown to prevent spam
- Use appropriate OTP length (4-8 digits)
- Test with screen readers for accessibility
This component is part of the ClawPlate suite and is optimized for modern authentication flows.
