Skip to main content
Vuetify0 is now a release candidate!
Vuetify0 Logo
Theme
Mode
Palettes
Accessibility
Vuetify One
Sign in to Vuetify One

Access premium tools across the Vuetify ecosystem — Bin, Play, Studio, and more.

Not a subscriber? See what's included

createOtp

Manage a fixed-length one-time-password or verification-code value with pattern-gated entry, length-based completion detection, and a decisional async hook. Headless — your component owns rendering, focus, and event wiring.

Usage

ts
import { createOtp } from '@vuetify/v0'

const otp = createOtp({
  length: 6,
  pattern: 'numeric',
  onComplete: async value => {
    const ok = await verify(value)
    return ok // false clears the value and surfaces an error
  },
})

otp.write(0, '4')          // single character at a position
otp.distribute('123456')   // distributes filtered characters
otp.value.value            // '412345' joined string
otp.isComplete.value       // true when length reached and all chars valid
otp.accepts('a')           // false under 'numeric'
otp.clear()

Architecture

createOtp Architecture

Use controls to zoom and pan. Click outside or press Escape to close.

createOtp Architecture

Layer 2 orchestrator. Aggregates createInput for validation, dirty tracking, and ARIA wiring. No registry, no focus traversal, no observers — rendering, per-element refs, and keyboard wiring are the consumer’s responsibility.

Options

Patterns

PatternMatches
'numeric'[0-9]
'alphanumeric'[a-zA-Z0-9]
'alphabetic'[a-zA-Z]
RegExpCustom; tested per character

accepts(char) is the single point of truth and is reactive through MaybeRefOrGetter — toggle modes at runtime and every helper respects the new pattern on the next call.

Reactivity

PropertyTypeReactiveDescription
valueReadonly<Ref<string>>Joined OTP string. Readonly — mutate via the helpers below.
lengthReadonly<Ref<number>>Target character count from the length option.
inputInputContext<string>Underlying createInput surface — ARIA IDs, errors, validation, focus/touched.
isCompleteReadonly<Ref<boolean>>true when value reaches length and every character passes accepts. Fires onComplete on the false → true edge.
write(index, char)(index: number, char: string) => voidWrites one character at index. Empty char truncates to value.slice(0, index) (Backspace mental model). Multi-character char is reduced to the first character — use distribute for multi-character input.
distribute(text, index?)(text: string, index?: number) => numberFilters text through accepts, splices at index (default 0), clips to length. Returns the count consumed so consumers can advance focus.
clear()() => voidEmpties the joined value.
fill(text)(text: string) => voidReplaces the joined value (filtered + clipped).
accepts(char)(char: string) => booleanPattern test, exposed so consumers can guard beforeinput.

Every helper is gated on the configured disabled and readonly options, and on the internal pending state while an async onComplete is in flight.

Examples

Email Verification Flow

A six-digit verification-code field with an async, decisional completion check. The composable owns the createOtp instance and a mock backend round-trip: onComplete resolves true to accept the code or false to reject it, clearing the value and surfacing input.errors. The component owns the per-cell <input> elements, the template refs, the focus advance, and the paste handler — focus and rendering are deliberately outside the composable. The entry wires the two together and renders a status line driven by isValidating, the rejection error, and a local verified flag.

Reach for this split when the verification step is more than a value capture: an async check that locks input while it runs, a rejection path that re-arms cleanly, and paste support that distributes a copied code across the cells in one keystroke. distribute returns how many characters it consumed so the component can land focus on the next empty slot, and while the async onComplete is pending every mutation helper no-ops — the user cannot race the verifier. Enter 424242 to pass; any other code exercises the reject-and-retry branch, where the first new keystroke clears the error automatically.

The tradeoffs mirror the headless contract. Because focus is rendering territory, the component wires it by hand; consumers who prefer roving focus can wrap the cells in useRovingFocus without touching the state model. A single wide input over the same createOtp works without modification — only the markup changes. See createInput for the validation, error, and field-state surface aggregated underneath, and createValidation for the rules array that flows through unchanged.

FileRole
useVerification.tsOwns the createOtp instance, the async onComplete backend check, and a derived status
VerificationCode.vueRenders the per-cell inputs and owns template refs, focus advance, backspace, and paste
verification-code.vueWires the composable to the component and renders the status line and reset control

Verify your email

Enter the 6-digit code we sent. The mock backend accepts 424242 — paste it to test distribute.

0 / 6 digits entered

FAQ

Discord
Need help? Join our community for support and discussions ↗

API Reference

The following API details are for the createOtp composable.
Was this page helpful?

Ctrl+/