UIInputOtp
UIInputOtp
A specialized input component designed for entering one-time passwords (OTP) with support for auto-focus, validation, and customization.
<template> <UIInputOtp v-model="otp" :length="6" :validateChar="validateNumeric" placeholder="Enter OTP" @complete="handleComplete" /></template>
<script setup lang="ts">const otp = ref('')
const validateNumeric = (char: string) => { return /^\d$/.test(char)}
const handleComplete = (value: string) => { console.log('OTP entered:', value)}</script>Props
modelValue(string): OTP valuelength(number): Number of OTP digitsvalidateChar(function): Character validation functionplaceholder(string): Input placeholderdisabled(boolean): Disable inputloading(boolean): Loading statetype(‘text’ | ‘number’ | ‘password’): Input typesize(‘sm’ | ‘md’ | ‘lg’): Input sizeautoFocus(boolean): Auto focus first inputsecure(boolean): Mask input as passwordinputClass(string): Input CSS classerror(boolean): Error state
Events
update:modelValue: Value updatedcomplete: OTP entry completedchange: Value changedfocus: Input focusedblur: Input blurredpaste: Value pasted
Slots
input: Custom input renderseparator: Custom separator contentprefix: Input prefix contentsuffix: Input suffix content
Usage Examples
- Basic OTP Input:
<template> <UIInputOtp v-model="otp" :length="4" /></template>
<script setup>const otp = ref('')</script>- Phone Verification:
<template> <div class="space-y-4"> <div class="text-center"> <h3 class="text-lg font-medium"> Verify Your Phone </h3>
<p class="text-gray-600"> Enter the 6-digit code sent to <span class="font-medium"> {{ formatPhone(phone) }} </span> </p> </div>
<UIInputOtp v-model="verificationCode" :length="6" :validateChar="validateNumeric" :loading="verifying" :error="!!error" placeholder="000000" class="justify-center" @complete="handleVerification" />
<div v-if="error" class="text-sm text-error-500 text-center" > {{ error }} </div>
<div class="text-center"> <button class="text-sm text-primary-600 hover:text-primary-500" :disabled="resendDisabled" @click="resendCode" > {{ resendText }} </button> </div> </div></template>
<script setup>const verificationCode = ref('')const verifying = ref(false)const error = ref('')const resendTimer = ref(30)const resendDisabled = computed(() => resendTimer.value > 0)const resendText = computed(() => { return resendDisabled.value ? `Resend code in ${resendTimer.value}s` : 'Resend code'})
const validateNumeric = (char: string) => { return /^\d$/.test(char)}
const handleVerification = async (code: string) => { verifying.value = true error.value = ''
try { await verifyPhone(code) // Handle success } catch (err) { error.value = err.message verificationCode.value = '' } finally { verifying.value = false }}
const startResendTimer = () => { resendTimer.value = 30 const interval = setInterval(() => { if (resendTimer.value > 0) { resendTimer.value-- } else { clearInterval(interval) } }, 1000)}
const resendCode = async () => { if (resendDisabled.value) return
try { await sendVerificationCode(phone) startResendTimer() } catch (err) { error.value = err.message }}
onMounted(() => { startResendTimer()})</script>- Two-Factor Authentication:
<template> <div class="space-y-6"> <div class="space-y-2"> <h3 class="text-lg font-medium"> Two-Factor Authentication </h3>
<p class="text-gray-600"> Enter the authentication code from your authenticator app </p> </div>
<UIInputOtp v-model="authCode" :length="6" :validateChar="validateNumeric" :secure="true" :size="'lg'" placeholder="••••••" class="justify-center" @complete="handleAuthentication" > <template #separator> <span class="text-gray-300 mx-2"> - </span> </template> </UIInputOtp>
<div class="flex items-center justify-between"> <button class="text-sm text-gray-600 hover:text-gray-900" @click="useBackupCode" > Use backup code </button>
<UIButton type="primary" :loading="authenticating" :disabled="authCode.length !== 6" @click="handleAuthentication" > Verify </UIButton> </div> </div></template>
<script setup>const authCode = ref('')const authenticating = ref(false)
const handleAuthentication = async () => { if (authCode.value.length !== 6) return
authenticating.value = true try { await verify2FA(authCode.value) // Handle success } catch (error) { // Handle error } finally { authenticating.value = false }}</script>Best Practices
-
User Experience:
- Auto focus
- Clear feedback
- Error handling
- Mobile optimization
-
Performance:
- Efficient updates
- Minimal reflows
- Memory management
- Input optimization
-
Accessibility:
- ARIA labels
- Keyboard navigation
- Screen reader support
- Focus management
-
Security:
- Input validation
- Secure input
- Rate limiting
- Error handling
Common Use Cases
- Email Verification:
<template> <div class="space-y-4"> <UIInputOtp v-model="emailCode" :length="6" :validateChar="validateNumeric" :error="!!error" placeholder="Enter code" @complete="verifyEmail" />
<div class="text-center text-sm"> <span class="text-gray-600"> Didn't receive the code? </span> <button class="text-primary-600 hover:text-primary-500 ml-1" @click="resendEmail" > Resend </button> </div> </div></template>- PIN Entry:
<template> <UIInputOtp v-model="pin" :length="4" :validateChar="validateNumeric" :secure="true" type="password" placeholder="••••" @complete="handlePinEntry" > <template #input="{ index, active }"> <div class="w-12 h-12 rounded-full border-2 flex items-center justify-center" :class="{ 'border-primary-500': active, 'border-gray-200': !active }" > • </div> </template> </UIInputOtp></template>- Confirmation Code:
<template> <div class="space-y-4"> <UIInputOtp v-model="confirmationCode" :length="8" :size="'lg'" class="justify-center" > <template #separator="{ index }"> <span v-if="(index + 1) % 4 === 0" class="mx-4 text-gray-300" > - </span> </template> </UIInputOtp>
<div class="flex justify-end space-x-2"> <UIButton variant="outline" @click="cancel" > Cancel </UIButton>
<UIButton type="primary" :disabled="confirmationCode.length !== 8" @click="confirm" > Confirm </UIButton> </div> </div></template>Component Composition
The UIInputOtp component works well with:
- UIButton for actions
- UISpinner for loading states
- UITooltip for help text
- UIIcon for status indicators
- UINotification for feedback
- UIModal for verification flows
- UIForm for validation
- UIAlert for error messages