Facebook Pixel

Building an OTP Input Component: A Complete Guide

OTP input with auto-focus, backspace, paste, and validation. Here is the complete implementation.

Building an OTP Input Component: A Complete Guide

The OTP input is a common authentication UI component. Here is the complete implementation with auto-focus, backspace, paste, and validation.

What an OTP Input Does

  • Multiple input boxes (4-6) for one digit each.
  • Auto-focus to the next box when a digit is entered.
  • Backspace moves to the previous box.
  • Paste fills all boxes.
  • Only numeric input allowed.
  • Auto-submit when all boxes are filled.

HTML Structure

<div class="otp-container" id="otpContainer"> <input type="text" maxlength="1" class="otp-input" inputmode="numeric" /> <input type="text" maxlength="1" class="otp-input" inputmode="numeric" /> <input type="text" maxlength="1" class="otp-input" inputmode="numeric" /> <input type="text" maxlength="1" class="otp-input" inputmode="numeric" /> </div> <button id="verifyBtn" disabled>Verify</button>

JavaScript Implementation

const inputs = document.querySelectorAll(".otp-input"); const verifyBtn = document.getElementById("verifyBtn"); inputs.forEach((input, index) => { // Auto-focus next on input input.addEventListener("input", (e) => { const value = e.target.value.replace(/\D/g, ""); e.target.value = value; if (value && index < inputs.length - 1) { inputs[index + 1].focus(); } checkComplete(); }); // Backspace to previous input.addEventListener("keydown", (e) => { if (e.key === "Backspace" && !e.target.value && index > 0) { inputs[index - 1].focus(); } }); // Paste support input.addEventListener("paste", (e) => { e.preventDefault(); const pasted = e.clipboardData.getData("text").replace(/\D/g, ""); pasted.split("").forEach((char, i) => { if (index + i < inputs.length) { inputs[index + i].value = char; } }); const nextIndex = Math.min(index + pasted.length, inputs.length - 1); inputs[nextIndex].focus(); checkComplete(); }); // Arrow key navigation input.addEventListener("keyup", (e) => { if (e.key === "ArrowLeft" && index > 0) inputs[index - 1].focus(); if (e.key === "ArrowRight" && index < inputs.length - 1) inputs[index + 1].focus(); }); }); function checkComplete() { const otp = Array.from(inputs).map((i) => i.value).join(""); verifyBtn.disabled = otp.length !== inputs.length; } function getOTP() { return Array.from(inputs).map((i) => i.value).join(""); }

CSS

.otp-container { display: flex; gap: 12px; justify-content: center; } .otp-input { width: 50px; height: 60px; font-size: 24px; text-align: center; border: 2px solid #ccc; border-radius: 8px; outline: none; } .otp-input:focus { border-color: #007bff; } .otp-input:focus-visible { box-shadow: 0 0 0 3px rgba(0,123,255,0.2); }

Features Summary

  1. Auto-focus to next on input.
  2. Backspace to previous when current is empty.
  3. Paste fills multiple boxes.
  4. Only numeric input (regex filter).
  5. Arrow key navigation.
  6. Auto-enable verify button when complete.
  7. Accessible (inputmode, focus states).

The Takeaway

The OTP input: HTML (multiple maxlength=1 inputs), JavaScript (auto-focus, backspace, paste, numeric filter, arrow keys, completion check), CSS (flexbox, focus styling). Key features: auto-focus, paste support, backspace navigation, and auto-submit. This is a common interview question testing DOM manipulation and event handling.

Create multiple input elements with maxlength=1. Add event listeners: input (auto-focus next, numeric only), keydown (backspace to previous), paste (fill multiple boxes), and keyup (arrow key navigation). Enable the verify button when all inputs are filled.

Listen for the paste event, prevent default, get the pasted text from clipboardData, filter to numeric only, and split each character across the input boxes starting from the current index. Focus the last filled input.

Listen for keydown. If the key is Backspace and the current input is empty, focus the previous input. This lets the user go back to correct a digit without clicking.

On the input event, replace non-numeric characters: e.target.value = e.target.value.replace(/\D/g, ''). Also set inputmode='numeric' on the input for mobile keyboards.

On each input event, check if all inputs have a value: Array.from(inputs).map(i => i.value).join('').length === inputs.length. If complete, enable the verify button or auto-trigger the submit.

Ready to master React completely?

Want to upskill yourself, crack your next interview, and get your dream job? Join our comprehensive course to dive deeper with high-quality video tutorials, solve interview questions, and a premium community.

Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.