How to Implement Keyboard Navigation in vue3-otp-input: Backspace, Arrows & Delete

vue3-otp-input provides built-in keyboard navigation that handles Backspace, Delete, and Arrow keys automatically through the handleOnKeyDown function in the parent component.

The ejirocodes/vue3-otp-input library is a Vue 3 component for one-time password entry that ships with full keyboard accessibility out of the box. Understanding how the internal navigation logic works—located in src/components/vue3-otp-input.vue—allows you to customize behavior or extend it with additional event listeners.

How Keyboard Navigation Works in vue3-otp-input

The component architecture separates concerns between a parent orchestrator and individual input cells. Keyboard events originate in single-otp-input.vue but are processed by the parent vue3-otp-input.vue.

Event flow:

  1. User presses a key in any <SingleOtpInput /> cell
  2. The child component emits the raw KeyboardEvent via @on-keydown
  3. The parent catches this in handleOnKeyDown(event, index) and executes navigation logic

The parent component maintains an activeInput ref (type number) that tracks which cell currently has focus. Helper methods focusNextInput(), focusPrevInput(), and focusInput(index) manage focus movement while clamping values between 0 and numInputs - 1.

Built-in Keyboard Controls

The library recognizes four primary navigation keys defined as constants in the source:

  • BACKSPACE = 8
  • LEFT_ARROW = 37
  • RIGHT_ARROW = 39
  • DELETE = 46

Backspace and Delete Behavior

When Backspace is pressed, the component:

  1. Prevents default browser behavior (event.preventDefault())
  2. Clears the current cell value via changeCodeAtFocus("")
  3. Moves focus to the previous input with focusPrevInput()

When Delete is pressed, the component only clears the current cell without moving focus, allowing users to remove a character and type a new one in place.

Arrow Key Navigation

Left Arrow triggers focusPrevInput(), moving the cursor to the previous cell if one exists. Right Arrow triggers focusNextInput(), advancing to the next cell. Both actions call event.preventDefault() to stop the browser from moving the text cursor within the input field.

Implementing Custom Keyboard Handlers

While the default behavior covers most accessibility needs, you can listen for additional keys (like Enter to submit) by catching the on-keydown event emitted by the component.

<template>
  <vue3-otp-input
    ref="otpInput"
    :num-inputs="6"
    v-model:value="otpValue"
    @on-keydown="handleKeydown"
    @on-complete="handleComplete"
  />
</template>

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

const otpValue = ref('');
const otpInput = ref<InstanceType<typeof VOtpInput> | null>(null);

const handleKeydown = (event: KeyboardEvent) => {
  if (event.key === 'Enter') {
    // Submit the OTP programmatically
    console.log('Submitting OTP:', otpValue.value);
    // Add your form submission logic here
  }
};

const handleComplete = (value: string) => {
  console.log('OTP complete:', value);
};
</script>

The on-keydown event forwards the native KeyboardEvent object, allowing you to check event.key, event.keyCode, or event.code for custom logic while preserving the built-in navigation behavior.

Source Code Reference

The keyboard navigation logic is split across two main component files:

The constants for key codes (BACKSPACE, LEFT_ARROW, RIGHT_ARROW, DELETE) are defined at the top of vue3-otp-input.vue and used in the switch statement within handleOnKeyDown.

Summary

  • vue3-otp-input provides built-in keyboard navigation for Backspace, Delete, and Arrow keys through the parent component's handleOnKeyDown method.
  • Backspace clears the current cell and moves focus left; Delete only clears the current cell.
  • Arrow keys move focus between cells while preventing default browser cursor movement.
  • The navigation state is managed via the activeInput ref in src/components/vue3-otp-input.vue.
  • You can extend functionality by listening to the on-keydown event for custom keys like Enter.

Frequently Asked Questions

Does vue3-otp-input support keyboard navigation by default?

Yes. The component ships with full keyboard accessibility enabled automatically. When users press Backspace, Delete, Left Arrow, or Right Arrow, the handleOnKeyDown function in src/components/vue3-otp-input.vue processes these events and manages focus movement between the individual input cells without requiring any additional configuration.

How do I prevent users from editing previous OTP fields?

Enable the should-focus-order prop on the component. When set to true, the component enforces a forward-only focus order, preventing users from navigating back to previous cells with arrow keys or backspace. The internal focusOrder method checks this prop before allowing focus changes initiated by user interaction.

Can I listen for the Enter key to submit the form?

Yes. While the component handles navigation keys internally, it emits the raw on-keydown event for every keystroke. Attach a listener to @on-keydown in your parent component and check for event.key === 'Enter' to trigger form submission or validation logic while maintaining the built-in navigation behavior.

Where is the keyboard navigation logic located in the source code?

The primary logic resides in src/components/vue3-otp-input.vue inside the handleOnKeyDown function, which uses constants for key codes (BACKSPACE=8, LEFT_ARROW=37, RIGHT_ARROW=39, DELETE=46) to determine whether to clear values or shift focus via focusNextInput() and focusPrevInput(). The child component at src/components/single-otp-input.vue forwards native keyboard events to the parent using emit('on-keydown', event).

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →