Input OTP

Stable v1.0.2

A segmented one-time-passcode input with auto-advance, backspace navigation, and paste-to-fill. Same label, error, and sizing behavior as every other form element in the library.

Interactive Playground

Every prop, wired live. Adjust length, masking, and character set and watch the code snippet update in real time.

Label & Position
Top
State
Length & Character Set
Appearance & Identity
Small (sm)
Live Source Code
<InputOtp
  v-model="value"
  id="custom-otp-id"
  label="Verification Code"
/>

Basic Usage

Six individual cells by default. Typing auto-advances to the next cell, and pasting a full code distributes it across all cells at once.

Template
<!-- Six numeric cells, auto-advance and paste built in -->
<InputOtp label="Verification Code" v-model="otpValue" />

<!-- Masked cells for a PIN re-entry flow -->
<InputOtp label="PIN" required mask v-model="pinValue" />

Validation & States

The error prop transforms every cell and intelligently maps over arrays to display multiple validation requirements, same as every other form element in the library.

That code has expired.
Request a new code and try again.
Template
<script setup>
const invalidErrors = ref([
  'That code has expired.',
  'Request a new code and try again.'
])
</script>

<template>
  <InputOtp
    label="Verification Code"
    v-model="otpValue"
    :error="invalidErrors"
  />
</template>

Input Sizing

Five carefully calibrated sizes, matching every other form element in the library.

Template
<InputOtp label="Extra Small" size="xs" />
<InputOtp label="Small" size="sm" />
<InputOtp label="Medium" size="md" />
<InputOtp label="Large" size="lg" />
<InputOtp label="Extra Large" size="xl" />

Length & Character Set

Set length for shorter codes, and :integer-only="false" to accept letters as well as digits.

Template
<InputOtp label="4-Digit PIN" :length="4" />

<InputOtp
  label="Backup Code"
  :length="8"
  :integer-only="false"
/>

API Reference

Props

Name
Type / Signature
Default
Description
modelValue
string
""
The concatenated passcode value, bound via v-model.
id
string
undefined
Overrides the auto-generated group id (useId()) used to derive each cell's id, e.g. for an external <label for> or test hooks.
label
string
undefined
Top or left-aligned input label.
labelPosition
"top" | "left"
"top"
Alignment of the label relative to the input cells.
required
boolean
false
Marks the field as required and renders an asterisk next to the label.
disabled
boolean
false
Disables user interaction and grays out every cell.
error
string | boolean | string[]
false
Applies red error styling and displays error message(s) below the cells.
length
number
6
Number of individual character cells rendered.
mask
boolean
false
Renders each cell as a masked dot instead of the entered character, for PIN-style codes.
integerOnly
boolean
true
Restricts input to numeric characters. Set to false to accept letters too.
size
"xs" | "sm" | "md" | "lg" | "xl"
"sm"
Dimensional size of each cell.

Events

Event Name
Payload Signature
Description
@focus
(event: FocusEvent)
Fired when a cell receives focus.
@blur
(event: FocusEvent)
Fired when a cell loses focus.
@input
(value: string)
Fired on every keystroke.
@change
(value: string)
Fired whenever the concatenated value changes.
@complete
(value: string)
Fired once every cell is filled.