Skip to content

Props & Events

Complete API reference for the <OtpInput> component.

Props

Core

PropTypeDefaultDescription
modelValuestring''v-model binding for the OTP value
numInputsnumber6Number of input fields
inputType'number' | 'tel' | 'letter-numeric' | 'password''tel'Input validation type
inputmodestring'numeric'HTML inputmode for virtual keyboard

Appearance

PropTypeDefaultDescription
themeOtpTheme'box'Visual theme (see Theming)
variant'default' | 'primary' | 'success' | 'danger' | 'warning''default'Color variant
size'sm' | 'md' | 'lg' | 'xl''md'Input size
placeholderstring | string[]''Placeholder (string for all, or array per-input)
separatorstring''HTML to render between inputs

State

PropTypeDefaultDescription
shouldAutoFocusbooleanfalseAuto-focus first input on mount
shouldFocusOrderbooleanfalseEnforce sequential input order
disabledbooleanfalseDisable all inputs
readonlybooleanfalseRead-only mode
errorbooleanfalseError state (triggers shake animation)
successbooleanfalseSuccess state (triggers pulse animation)

Styling

PropTypeDefaultDescription
inputClassesstring | string[]''CSS classes for each input
conditionalClassstring[] | (index, value) => stringPer-input classes (array or function)
containerClassstring''CSS class for the container
ariaLabelstring'OTP Input'Accessible label

Theme Type

ts
type OtpTheme =
  | 'box'        // Clean bordered with rounded corners
  | 'underline'  // Minimal bottom-border
  | 'rounded'    // Circular inputs
  | 'pill'       // Capsule-shaped
  | 'separated'  // Elevated cards with lift
  | 'flush'      // Joined continuous bar
  | 'shadow'     // Prominent shadow
  | 'neon'       // Glowing on dark background
  | 'glass'      // Glassmorphism with blur
  | 'minimal'    // Thin borders, ultra clean
  | 'filled'     // Solid background, no border

Events

EventPayloadDescription
update:modelValuestringEvery change (v-model support)
changestringEvery character change
completestringAll inputs filled
vue
<OtpInput
  v-model="otp"
  @change="onEveryChange"
  @complete="onAllFilled"
/>

Exposed Methods

Access via a template ref:

vue
<script setup>
import { ref } from 'vue'
import { OtpInput } from 'vue-otp-pro'

const otpRef = ref<InstanceType<typeof OtpInput> | null>(null)

// Available methods:
otpRef.value?.clear()        // Clear all inputs, focus first
otpRef.value?.fill('123456') // Fill all inputs
otpRef.value?.focus()        // Focus the first input
otpRef.value?.focusInput(3)  // Focus a specific input by index
</script>

<template>
  <OtpInput ref="otpRef" />
</template>
MethodArgumentsDescription
clear()Clears all inputs and focuses the first one
fill(value)stringFills inputs with the given value
focus()Focuses the first input
focusInput(index)numberFocuses a specific input by index

Slots

separator

Override the default separator with custom content:

vue
<OtpInput separator="-">
  <template #separator>
    <span style="color: #6366f1; font-weight: bold;">-</span>
  </template>
</OtpInput>

Conditional Classes

Array mode

Pass an array where each index maps to an input:

vue
<OtpInput :conditional-class="['first', '', '', '', '', 'last']" />

Function mode

Pass a function for dynamic per-input styling:

vue
<OtpInput
  :conditional-class="(index, value) =>
    value ? 'has-value' : 'empty'
  "
/>

TypeScript

All types are exported:

ts
import type {
  OtpInputProps,
  OtpInputExpose,
  OtpInputType,
  OtpTheme,
  OtpVariant,
  OtpSize,
} from 'vue-otp-pro'