Lightweight Vue 3 Two-Factor Authentication input component with full keyboard navigation
npm install @flbx/vue-otp-inputLightweight Vue 3 OTP/2FA input component with full keyboard navigation, paste support, and accessibility.
- Lightweight — ~1.4KB gzipped JS + ~0.4KB CSS
- Zero dependencies — Vue 3 only
- TypeScript — Fully typed
- Keyboard navigation — Arrow keys, Backspace, Delete
- Paste support — Paste full OTP codes
- Auto-focus — Moves to next field automatically
- Accessible — ARIA labels included
- Mobile-friendly — Numeric keyboard
``bashpnpm
pnpm add @flbx/vue-otp-input
Usage
$3
`vue
`$3
`vue
v-model="code"
:length="6"
@complete="submit"
/>
`$3
`vue
`API Reference
$3
| Prop | Type | Default | Description |
|------|------|---------|-------------|
|
v-model | string | '' | The OTP code value |
| length | 4 \| 5 \| 6 | 6 | Number of digits |
| disabled | boolean | false | Disable inputs |$3
| Event | Payload | Description |
|-------|---------|-------------|
|
update:modelValue | string | Fires on each digit change |
| complete | string | Fires when all digits are filled |Styling
$3
`ts
import '@flbx/vue-otp-input/style.css'
`$3
| Class | Description |
|-------|-------------|
|
.tfa-input | Container (flexbox) |
| .tfa-input--disabled | When disabled |
| .tfa-input__field | Each input field |$3
`css
.tfa-input {
gap: 1rem;
}.tfa-input__field {
width: 3rem;
height: 3rem;
font-size: 1.5rem;
border: 2px solid #e2e8f0;
border-radius: 8px;
}
.tfa-input__field:focus {
border-color: #3b82f6;
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.3);
}
`Composable
For custom implementations, use
useTfaInput directly.$3
| Option | Type | Required | Description |
|--------|------|----------|-------------|
|
length | number | Yes | Number of digits |
| modelValue | Ref | Yes | Reactive ref for the value |
| onComplete | (value: string) => void | No | Called when all digits filled |$3
| Property | Type | Description |
|----------|------|-------------|
|
inputRefs | TemplateRefsList | Refs for input elements |
| digits | Ref | Array of individual digits (readonly) |
| onInput | Function | Bind to @input |
| onKeydown | Function | Bind to @keydown |
| onFocus | Function | Bind to @focus |
| onPaste | Function | Bind to @paste |$3
`vue
v-for="(digit, index) in digits"
:key="index"
:ref="inputRefs.set"
:value="digit"
type="text"
inputmode="numeric"
maxlength="1"
@input="onInput(index, $event)"
@keydown="onKeydown(index, $event)"
@focus="onFocus"
@paste="onPaste(index, $event)"
/>
`Types
`ts
import type { UseTfaInputOptions, UseTfaInputReturn } from '@flbx/vue-otp-input'
``MIT © Florian Beaumont