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:
- User presses a key in any
<SingleOtpInput />cell - The child component emits the raw
KeyboardEventvia@on-keydown - 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 = 8LEFT_ARROW = 37RIGHT_ARROW = 39DELETE = 46
Backspace and Delete Behavior
When Backspace is pressed, the component:
- Prevents default browser behavior (
event.preventDefault()) - Clears the current cell value via
changeCodeAtFocus("") - 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:
-
src/components/vue3-otp-input.vue– Contains thehandleOnKeyDownfunction,activeInputstate management, and focus helper methods (focusNextInput,focusPrevInput,changeCodeAtFocus). -
src/components/single-otp-input.vue– Renders the individual<input>element and forwards keyboard events to the parent viaemit('on-keydown', event).
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
handleOnKeyDownmethod. - 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
activeInputref insrc/components/vue3-otp-input.vue. - You can extend functionality by listening to the
on-keydownevent 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →