How to Integrate vue3-otp-input with Vue 3 Composition API: Complete Guide
You can integrate vue3-otp-input with the Vue 3 Composition API by importing the component into your <script setup> block, binding the OTP value via v-model:value, listening to on-change and on-complete events, and accessing exposed methods like clearInput through template refs.
The vue3-otp-input library by ejirocodes provides a modern, accessible one-time password input component built specifically for Vue 3. Since the component is authored using the <script setup> syntax and Composition API primitives, it integrates seamlessly with Vue 3 projects using the same paradigm. This guide demonstrates how to integrate vue3-otp-input with the Vue 3 Composition API using local registration, global registration, and programmatic control via template references.
Understanding the vue3-otp-input Component Architecture
The component is implemented as a single-file component in src/components/vue3-otp-input.vue using Vue 3's <script setup> syntax. It leverages defineProps for type-safe property declarations, defineEmits for event definitions including update:value, on-change, and on-complete, and defineExpose to make clearInput and fillInput methods accessible to parent components.
The internal state management uses standard Composition API refs (activeInput, otp, oldOtp) and watchers to handle input synchronization across the individual digit fields rendered by the child component src/components/single-otp-input.vue.
Step-by-Step Integration with Vue 3 Composition API
Local Component Registration
Import the component directly into your parent component's <script setup> block. This is the recommended approach for tree-shaking and scoped usage.
<script setup lang="ts">
import { ref } from "vue";
import VOtpInput from "vue3-otp-input";
const otpValue = ref("");
const otpInput = ref<InstanceType<typeof VOtpInput> | null>(null);
function handleComplete(value: string) {
console.log("OTP completed:", value);
}
</script>
<template>
<v-otp-input
ref="otpInput"
v-model:value="otpValue"
:num-inputs="4"
@on-complete="handleComplete"
/>
</template>
Global Registration
For applications requiring the OTP input across multiple components, register it globally in your entry file main.ts.
// main.ts
import { createApp } from "vue";
import App from "./App.vue";
import VOtpInput from "vue3-otp-input";
const app = createApp(App);
// Register globally as <v-otp-input>
app.component("v-otp-input", VOtpInput);
app.mount("#app");
Binding OTP Values with v-model:value
The component uses a custom v-model argument named value. Bind your reactive ref to v-model:value to enable two-way data binding. The component emits update:value events internally to synchronize state.
<script setup lang="ts">
import { ref } from "vue";
import VOtpInput from "vue3-otp-input";
const bindValue = ref("");
</script>
<template>
<v-otp-input
v-model:value="bindValue"
:num-inputs="6"
input-classes="otp-input"
/>
</template>
Handling Events: on-change and on-complete
The component emits two primary events: on-change fires on every digit entry with the current OTP string value, and on-complete fires when the last digit is filled, providing the complete OTP string for immediate validation or API submission.
<script setup lang="ts">
import { ref } from "vue";
import VOtpInput from "vue3-otp-input";
const otp = ref("");
function handleOnChange(val: string) {
console.log("OTP changed:", val);
}
function handleOnComplete(val: string) {
console.log("OTP completed:", val);
// Submit to API or validate
}
</script>
<template>
<v-otp-input
v-model:value="otp"
:num-inputs="4"
@on-change="handleOnChange"
@on-complete="handleOnComplete"
/>
</template>
Accessing Exposed Methods via Template Refs
To programmatically control the input, create a template ref typed as InstanceType<typeof VOtpInput>. The component exposes clearInput() to reset all fields and fillInput(value: string) to programmatically populate the OTP, useful for auto-fill or reset functionality.
<script setup lang="ts">
import { ref } from "vue";
import VOtpInput from "vue3-otp-input";
const otpInput = ref<InstanceType<typeof VOtpInput> | null>(null);
const otpValue = ref("");
function clear() {
otpInput.value?.clearInput(); // clears all inputs
}
function fill() {
otpInput.value?.fillInput("1234"); // fills with a complete OTP
}
</script>
<template>
<div>
<v-otp-input
ref="otpInput"
v-model:value="otpValue"
:num-inputs="4"
/>
<button @click="clear()">Clear Input</button>
<button @click="fill()">Fill Input</button>
</div>
</template>
Complete Working Example
Here is a complete, runnable single-file component demonstrating local registration, event handling, programmatic control, and styling.
<!-- DemoOtp.vue -->
<script setup lang="ts">
import { ref } from "vue";
import VOtpInput from "vue3-otp-input";
const otpRef = ref<InstanceType<typeof VOtpInput> | null>(null);
const otp = ref("");
function onComplete(val: string) {
alert(`OTP entered: ${val}`);
}
function resetOtp() {
otpRef.value?.clearInput();
}
function autoFill() {
otpRef.value?.fillInput("987654");
}
</script>
<template>
<div class="otp-container">
<VOtpInput
ref="otpRef"
v-model:value="otp"
:num-inputs="6"
input-classes="otp-input"
:placeholder="['*', '*', '*', '*', '*', '*']"
:should-auto-focus="true"
@on-complete="onComplete"
/>
<div class="controls">
<button @click="resetOtp">Clear</button>
<button @click="autoFill">Auto-fill</button>
</div>
<p>Current value: {{ otp }}</p>
</div>
</template>
<style>
.otp-container {
display: flex;
flex-direction: column;
align-items: center;
gap: 20px;
padding: 20px;
}
.otp-input {
width: 40px;
height: 40px;
font-size: 20px;
text-align: center;
border: 2px solid #ccc;
border-radius: 4px;
margin: 0 5px;
}
.otp-input:focus {
border-color: #007bff;
outline: none;
}
.controls {
display: flex;
gap: 10px;
}
button {
padding: 8px 16px;
cursor: pointer;
}
</style>
Summary
- vue3-otp-input is built with
<script setup>and Composition API primitives (ref,watch,defineProps,defineEmits), ensuring native compatibility with Vue 3 projects using the same paradigm. - Import the component from
vue3-otp-inputand register it locally in<script setup>or globally inmain.tsviaapp.component(). - Use
v-model:valueto bind the OTP string reactively; the component handles internal state viaupdate:valueemissions as defined insrc/components/vue3-otp-input.vue. - Listen to
on-changefor real-time updates during digit entry andon-completefor final submission triggers when the last field is filled. - Access
clearInputandfillInputmethods through a typed template ref (InstanceType<typeof VOtpInput>) for programmatic control of the OTP state.
Frequently Asked Questions
Does vue3-otp-input work with Vue 3 Composition API?
Yes, the component is authored using <script setup> syntax and Composition API primitives including ref, watch, defineProps, and defineEmits. It is designed specifically for Vue 3 and integrates seamlessly with parent components using the Composition API, as evidenced by its implementation in src/components/vue3-otp-input.vue.
How do I clear the OTP input programmatically?
Create a template ref typed as InstanceType<typeof VOtpInput> and call the exposed clearInput() method. This resets all digit fields and internal state to empty strings. The method is exposed via defineExpose({ clearInput, fillInput }) in the component source, making it available through the component ref.
What events does vue3-otp-input emit?
The component emits three primary events: update:value (used internally for v-model:value synchronization), on-change (fired on every digit entry with the current OTP string value), and on-complete (fired when the last digit is filled, providing the complete OTP string for validation or API submission).
Can I use vue3-otp-input with TypeScript?
Yes, the component is written in TypeScript and exports type definitions. When using template refs, type them as InstanceType<typeof VOtpInput> to access exposed methods with full IntelliSense support. The props and events are fully typed through defineProps and defineEmits declarations in the source code.
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 →