Skip to content

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

OTP Code Form Component 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

PropTypeDefaultDescription
titlestring'Enter Verification Code'Form title
descriptionstring'We sent a 6-digit code to your email'Form description
submitTextstring'Verify Code'Submit button text
loadingTextstring'Verifying...'Loading button text
resendTextstring'Resend Code'Resend button text
lengthnumber6Number of OTP digits
autoSubmitbooleantrueAuto-submit when complete
loadingbooleanfalseLoading state
errorMessagestring''Error message to display
resendCooldownnumber0Resend cooldown in seconds
typestringChoose between SMS or EMAIL to switch Icons

Events

EventPayloadDescription
submitcode: stringEmitted when form is submitted
resend-Emitted when resend button is clicked
completecode: stringEmitted when code is complete
changecode: stringEmitted 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

  1. Always provide clear instructions in the description
  2. Handle errors gracefully with user-friendly messages
  3. Implement resend cooldown to prevent spam
  4. Use appropriate OTP length (4-8 digits)
  5. Test with screen readers for accessibility

This component is part of the ClawPlate suite and is optimized for modern authentication flows.

Built with love by mhdevfr