# How to Use v-model with vue3-otp-input for Two-Way Data Binding

> Learn how to use v-model with vue3-otp-input for two-way data binding. Bind OTP values reactively using the v-model value prop for seamless integration.

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

---

**Use the named v-model syntax `v-model:value="otpValue"` to bind the OTP string reactively, because the component exposes a `value` prop and emits `update:value` events.**

The `vue3-otp-input` library provides a customizable one-time password input component for Vue 3 applications. To integrate it seamlessly with your form state, you need to understand how to use v-model with vue3-otp-input for proper two-way data binding. This guide explains the internal contract between the component's props and events, sourced directly from the repository's implementation.

## Understanding the v-model Contract in vue3-otp-input

The component implements Vue 3's custom v-model convention through a specific prop-event pair defined in [`src/components/vue3-otp-input.vue`](https://github.com/ejirocodes/vue3-otp-input/blob/main/src/components/vue3-otp-input.vue).

### The `value` Prop

The component accepts a **prop named `value`** of type `string` (declared at lines 11-14). This prop represents the current OTP value controlled by the parent component.

### The `update:value` Event

To communicate changes back to the parent, the component **emits `update:value`** using Vue 3's `defineEmits` macro (defined at lines 45-48). This event fires whenever the internal OTP array changes, such as when a user types or pastes a code.

### Internal Synchronization

The component maintains an internal reactive `otp` array that syncs with the external `value` prop through a watcher (implemented at lines 55-63). When the parent updates the bound value, the watcher detects the change and updates the internal state, ensuring the UI reflects the new OTP string immediately.

## Implementing Two-Way Binding with v-model:value

Because the component uses `value` instead of the default `modelValue`, you must use the **named v-model syntax** `v-model:value`.

### Basic Usage Example

Here is the minimal implementation to bind a reactive reference to the OTP input:

```vue
<script setup lang="ts">
import { ref } from "vue";
import Vue3OtpInput from "vue3-otp-input";

const bindValue = ref("");  // Reactive OTP string
</script>

<template>
  <vue3-otp-input
    v-model:value="bindValue"
    :num-inputs="6"
    input-classes="otp-box"
  />
  <p>Current OTP: {{ bindValue }}</p>
</template>

<style>
.otp-box {
  width: 2.5rem;
  text-align: center;
  margin: 0 0.25rem;
}
</style>

```

In this example, every keystroke inside the OTP fields automatically updates `bindValue`, and the paragraph below displays the live value.

### Advanced Usage with Events and Refs

For scenarios requiring programmatic control or event handling, combine `v-model:value` with component references and event listeners:

```vue
<script setup lang="ts">
import { ref, unref } from "vue";
import Vue3OtpInput from "vue3-otp-input";

const otpRef = ref<InstanceType<typeof Vue3OtpInput> | null>(null);
const bindValue = ref("");

function onComplete(val: string) {
  console.log("OTP completed:", val);
  // Trigger form submission or API call
}

function onChange(val: string) {
  console.log("OTP changed:", val);
}
</script>

<template>
  <vue3-otp-input
    ref="otpRef"
    v-model:value="bindValue"
    :num-inputs="4"
    separator="-"
    inputType="letter-numeric"
    :should-auto-focus="true"
    @on-complete="onComplete"
    @on-change="onChange"
  />
  
  <div class="controls">
    <button @click="unref(otpRef)?.clearInput()">Clear Input</button>
    <button @click="unref(otpRef)?.fillInput('12AB')">Fill Input</button>
  </div>
  
  <p>Bound value: {{ bindValue }}</p>
</template>

```

This implementation demonstrates:

- **Two-way binding** via `v-model:value` keeps `bindValue` synchronized.
- **Programmatic control** using `clearInput()` and `fillInput()` methods exposed through `defineExpose` in the component source (lines 13-16).
- **Event handling** for `on-complete` and `on-change` to execute logic when the user finishes entering the code or modifies it.

## Programmatic Control and Resetting Values

When you need to reset the OTP from the parent component, simply mutate the bound reactive reference. The component watches the `value` prop and synchronizes its internal `otp` array accordingly.

```typescript
// In parent component
bindValue.value = "";  // Clears all input fields immediately

```

This works because of the watcher defined in [`src/components/vue3-otp-input.vue`](https://github.com/ejirocodes/vue3-otp-input/blob/main/src/components/vue3-otp-input.vue) at lines 55-63, which detects external changes to the `value` prop and updates the internal state to match.

## Summary

- Use the **named v-model syntax** `v-model:value` to bind data to `vue3-otp-input` because the component exposes a `value` prop and emits `update:value` events.
- The component implements **full two-way binding**: parent updates reflect in the UI, and user input updates the parent state.
- Access **programmatic methods** like `clearInput()` and `fillInput()` by assigning a template ref to the component instance.
- Reset the OTP by mutating the bound reactive value; the component automatically synchronizes its internal state via prop watchers defined in [`src/components/vue3-otp-input.vue`](https://github.com/ejirocodes/vue3-otp-input/blob/main/src/components/vue3-otp-input.vue).

## Frequently Asked Questions

### Why does vue3-otp-input use `v-model:value` instead of standard `v-model`?

Vue 3's default v-model uses a prop named `modelValue` and an event named `update:modelValue`. However, `vue3-otp-input` was designed with an explicit `value` prop to match traditional input element APIs. Therefore, you must use the named v-model syntax `v-model:value` to tell Vue which prop to bind to. This is fully supported in Vue 3 and provides the same two-way binding behavior.

### How do I clear the OTP input programmatically?

You have two options to clear the input. First, mutate the bound reactive reference directly: `myOtpValue.value = ""`. This triggers the component's internal watcher and clears all fields. Alternatively, assign a template ref to the component and call the exposed `clearInput()` method: `otpRef.value?.clearInput()`. Both methods reset the internal `otp` array and update the UI immediately.

### Can I use v-model with TypeScript and vue3-otp-input?

Yes, TypeScript support is fully available. Import the component type and use `InstanceType<typeof Vue3OtpInput>` when creating template refs. The `v-model:value` binding works with `ref<string>` types, and the component's emitted events are properly typed in the source. Ensure you import the component correctly: `import Vue3OtpInput from "vue3-otp-input"`.

### What happens if I change the bound value from the parent component?

When you update the reactive value bound to `v-model:value` from the parent, the component detects the change through its internal watcher on the `value` prop (defined at lines 55-63 in [`src/components/vue3-otp-input.vue`](https://github.com/ejirocodes/vue3-otp-input/blob/main/src/components/vue3-otp-input.vue)). The watcher then updates the internal `otp` array to match the new string value, causing the individual input fields to update their display accordingly. This ensures the UI always stays synchronized with the parent state.