How to Handle Paste Events for OTP Input with Automatic Field Population in Vue 3
The vue3-otp-input component automatically intercepts paste events, validates the clipboard data against your configured input type, distributes characters across remaining fields, and emits the completed value without requiring manual event listeners.
Handling paste events for one-time password (OTP) inputs requires careful coordination between individual input fields and the parent component. The vue3-otp-input library implements a robust paste handling mechanism that works across desktop and mobile browsers, including a specific workaround for iOS SMS autofill. This guide explains the architectural flow, implementation details, and practical usage based on the actual source code in the ejirocodes/vue3-otp-input repository.
Architecture of Paste Handling in vue3-otp-input
Component Hierarchy and Event Flow
The library uses a two-layer architecture to manage paste events:
- Wrapper component (
src/components/vue3-otp-input.vue): Manages theotparray, tracks theactiveInputindex, and implements the mainhandleOnPastelogic. - Single input component (
src/components/single-otp-input.vue): Renders individual digit fields and forwards paste events, including synthetic events for iOS compatibility.
When a user pastes content, the single input captures the native event and emits it to the wrapper, which then processes the clipboard data, validates it, and distributes values across the OTP array.
The Paste Handling Flow
The handleOnPaste function in the wrapper component executes the following sequence:
- Prevent default behavior to stop browser-native pasting into a single field.
- Extract clipboard data using
event.clipboardData.getData("text/plain"), truncated to the number of remaining empty slots (numInputs - activeInput). - Validate input type against configured
inputType(number, letter-numeric, etc.) using regex patterns. - Merge with existing data by concatenating already-entered characters with the new pasted values.
- Update OTP array and shift focus to the next empty field using
focusInput. - Emit completion events (
update:valueandon-complete) when all fields are filled.
Implementation Details and Source Code
Wrapper Paste Logic in vue3-otp-input.vue
The main paste handler resides in src/components/vue3-otp-input.vue. Here is the core implementation:
const handleOnPaste = (event: any) => {
event.preventDefault();
const pastedData = event.clipboardData
.getData("text/plain")
.slice(0, props.numInputs - activeInput.value)
.split("");
// Type-specific validation
if (props.inputType === "number" && !pastedData.join("").match(/^\d+$/)) {
return "Invalid pasted data";
}
if (props.inputType === "letter-numeric" && !pastedData.join("").match(/^\w+$/)) {
return "Invalid pasted data";
}
// Merge with already-filled characters and write back
const currentCharsInOtp = otp.value.slice(0, activeInput.value);
const combinedWithPastedData = currentCharsInOtp.concat(pastedData);
combinedWithPastedData.slice(0, props.numInputs).forEach((value, i) => {
otp.value[i] = value;
});
// Focus next empty input and emit change/completion events
focusInput(combinedWithPastedData.slice(0, props.numInputs).length);
return checkFilledAllInputs();
};
This function handles edge cases such as partial pastes (pasting "12" into the third field of a six-digit OTP) and over-length pastes (truncating "123456789" to fit remaining slots).
iOS SMS Autofill Workaround in single-otp-input.vue
Mobile Safari's SMS autofill does not always fire standard paste events. The component in src/components/single-otp-input.vue detects multi-character inputs and synthesizes a clipboard event:
if (value && value.trim().length > 1) {
// iOS does not fire a native onPaste when SMS autofills.
// Create a synthetic clipboard event so the wrapper can handle it.
e.clipboardData = {
getData: () => value.trim(),
};
return emit("on-paste", e as ClipboardEvent);
}
return emit("on-change", value);
When detected, it constructs a synthetic ClipboardEvent with a getData method returning the autofilled value, then emits this as an on-paste event. This ensures that iOS users experience the same automatic field population as desktop users who manually paste.
Practical Usage Example
To enable automatic field population via paste events, install the component and bind it to your form:
npm install vue3-otp-input
Then implement the component in your Vue 3 template:
<template>
<Vue3OtpInput
v-model="otpCode"
:numInputs="6"
inputType="number"
separator="-"
shouldAutoFocus
@on-complete="handleComplete"
/>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import Vue3OtpInput from 'vue3-otp-input';
const otpCode = ref('');
const handleComplete = (value: string) => {
console.log('OTP completed:', value);
// Submit to verification API
};
</script>
Behavior when pasting "123456":
- User pastes into any input field (or iOS autofills).
single-otp-inputcaptures the event and forwards it to the wrapper.handleOnPastevalidates the numeric format, splits the string, and populatesotparray indices 0-5.- Focus shifts to the final field.
on-completeevent fires with value"123456", andv-modelupdates simultaneously.
Handling Edge Cases
The component automatically manages several paste scenarios without additional configuration:
- Partial paste: Pasting "45" into the third field of a six-digit OTP fills slots 2 and 3, leaving slots 4-5 empty for manual entry.
- Over-length paste: Pasting "123456789" into a 6-digit input truncates to "123456", discarding excess characters.
- Invalid characters: When
inputType="number", pasting "12ab34" aborts the operation and returns "Invalid pasted data", leaving existing inputs unchanged. - iOS SMS autofill: The synthetic event workaround ensures auto-populated codes from text messages trigger the same distribution logic as manual pastes.
Summary
- Automatic distribution: The
handleOnPastefunction insrc/components/vue3-otp-input.vueintercepts clipboard data, validates it against the configuredinputType, and distributes characters across the OTP array. - iOS compatibility:
src/components/single-otp-input.vuedetects multi-character SMS autofill events and synthesizes aClipboardEventto ensure consistent handling across platforms. - Zero configuration: Paste handling works immediately upon installing the component, managing edge cases like partial pastes, over-length strings, and invalid characters automatically.
- Event emission: Successful paste operations trigger
update:valueforv-modelbinding andon-completewhen all fields are filled, enabling seamless form integration.
Frequently Asked Questions
How does vue3-otp-input handle paste events differently from native HTML inputs?
Unlike standard HTML inputs that paste content into a single field, vue3-otp-input intercepts the paste event at the wrapper level via handleOnPaste in src/components/vue3-otp-input.vue. It extracts the clipboard data, validates it against the inputType regex (number or letter-numeric), splits the string into individual characters, and distributes them across the remaining empty input slots. This ensures that pasting "123456" into any field of a 6-digit OTP automatically fills all six fields sequentially.
Why is there a special workaround for iOS SMS autofill in the single-otp-input component?
iOS Safari's SMS autofill feature does not consistently fire native paste events when suggesting OTP codes from messages. To handle this, src/components/single-otp-input.vue monitors input changes for values longer than one character. When detected, it constructs a synthetic ClipboardEvent with a getData method returning the autofilled value, then emits this as an on-paste event. This ensures that iOS users experience the same automatic field population as desktop users who manually paste.
What happens when a user pastes more characters than remaining OTP fields?
The handleOnPaste function automatically truncates over-length paste data to fit the remaining available slots. Specifically, it slices the clipboard string using props.numInputs - activeInput.value, ensuring that only enough characters to fill the empty fields are processed. For example, pasting "123456789" into the first field of a 6-digit OTP will only use "123456", discarding the excess "789" without error or notification to the user.
How can I validate pasted content before it populates the OTP fields?
The component performs built-in validation based on the inputType prop. When inputType is set to "number", the paste handler checks if the clipboard data matches /^\d+$/ (digits only). For "letter-numeric", it validates against /^\w+$/ (alphanumeric). If validation fails, the function returns "Invalid pasted data" and aborts the operation, leaving existing inputs unchanged. For custom validation logic, you would need to fork the component and modify the handleOnPaste function in src/components/vue3-otp-input.vue before the standard validation checks.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →