# How to Integrate vue3-otp-input with Vue 3 Composition API: Complete Guide

> Integrate vue3-otp-input with Vue 3 Composition API using <script setup> and v-model value binding. Learn to handle OTP changes and completions with this complete guide.

- Repository: [Ejiro Asiuwhu/vue3-otp-input](https://github.com/ejirocodes/vue3-otp-input)
- Tags: how-to-guide
- Published: 2026-03-01

---

**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`](https://github.com/ejirocodes/vue3-otp-input/blob/main/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`](https://github.com/ejirocodes/vue3-otp-input/blob/main/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.

```vue
<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`](https://github.com/ejirocodes/vue3-otp-input/blob/main/main.ts).

```typescript
// 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.

```vue
<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.

```vue
<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.

```vue
<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.

```vue
<!-- 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-input` and register it locally in `<script setup>` or globally in [`main.ts`](https://github.com/ejirocodes/vue3-otp-input/blob/main/main.ts) via `app.component()`.
- Use `v-model:value` to bind the OTP string reactively; the component handles internal state via `update:value` emissions as defined in [`src/components/vue3-otp-input.vue`](https://github.com/ejirocodes/vue3-otp-input/blob/main/src/components/vue3-otp-input.vue).
- Listen to `on-change` for real-time updates during digit entry and `on-complete` for final submission triggers when the last field is filled.
- Access `clearInput` and `fillInput` methods 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`](https://github.com/ejirocodes/vue3-otp-input/blob/main/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.