JS Guide
HomeQuestionsTopicsCompaniesResources
BookmarksSearch

Built for developers preparing for JavaScript, React & TypeScript interviews.

ResourcesQuestionsSupport
HomeQuestionsSearchProgress
HomeQuestionsreact
PrevNext

Learn the concept

Forms

react
mid
machine-coding

Build an OTP (One-Time Password) input component in React that auto-advances focus between fields, supports paste, and handles backspace navigation.

react
machine-coding
forms
focus-management
accessibility
otp
interview
Quick Answer

An OTP input renders N separate single-character inputs with automatic focus management — advancing on input, reversing on backspace, and handling clipboard paste to distribute digits across all fields.

Detailed Explanation

Core Requirements:

  • Render a configurable number of single-character input fields (typically 4 or 6)
  • Auto-advance focus to the next input when a digit is entered
  • Move focus back on Backspace when the current field is empty
  • Handle paste events by distributing pasted characters across all fields
  • Call an onComplete callback when all fields are filled

Focus Management: Use an array of refs (useRef) to hold references to each input element. On every onChange, check if a value was entered — if so, call nextInput.focus(). On onKeyDown for Backspace, if the current field is empty, focus the previous field.

Paste Handling: Intercept the onPaste event on the container or individual inputs. Extract the pasted text, split into characters, and set each input's value in sequence. Then focus the first empty field or the last field.

Edge Cases:

  • Non-numeric input: filter to digits only (or alphanumeric depending on OTP type)
  • Overwrite: if the user types in a field that already has a value, replace it and advance
  • Middle-field editing: allow the user to click any field and edit it without breaking the flow
  • Mobile: set inputMode="numeric" and autoComplete="one-time-code" for native OTP autofill

Accessibility:

  • Use aria-label="Digit N of M" on each input
  • Wrap inputs in a role="group" with an aria-labelledby pointing to a visible label
  • Support keyboard-only interaction (Tab, Shift+Tab, arrow keys)
  • Announce completion to screen readers via aria-live region

Code Examples

OTP Input component with focus management and paste supportJSX
import { useRef, useState, useCallback } from 'react';

function OTPInput({ length = 6, onComplete }) {
  const [values, setValues] = useState(Array(length).fill(''));
  const inputRefs = useRef([]);

  const focusInput = (index) => {
    const clamped = Math.max(0, Math.min(index, length - 1));
    inputRefs.current[clamped]?.focus();
  };

  const handleChange = useCallback((index, e) => {
    const char = e.target.value.slice(-1); // Take last character typed
    if (char && !/^\d$/.test(char)) return; // Digits only

    const next = [...values];
    next[index] = char;
    setValues(next);

    if (char && index < length - 1) {
      focusInput(index + 1);
    }

    const otp = next.join('');
    if (otp.length === length && next.every(Boolean)) {
      onComplete?.(otp);
    }
  }, [values, length, onComplete]);

  const handleKeyDown = useCallback((index, e) => {
    if (e.key === 'Backspace') {
      if (!values[index] && index > 0) {
        // Current field empty — clear previous and focus it
        const next = [...values];
        next[index - 1] = '';
        setValues(next);
        focusInput(index - 1);
      } else {
        // Clear current field
        const next = [...values];
        next[index] = '';
        setValues(next);
      }
    } else if (e.key === 'ArrowLeft') {
      focusInput(index - 1);
    } else if (e.key === 'ArrowRight') {
      focusInput(index + 1);
    }
  }, [values, length]);

  const handlePaste = useCallback((e) => {
    e.preventDefault();
    const pasted = e.clipboardData.getData('text').replace(/\D/g, '');
    const chars = pasted.slice(0, length).split('');
    const next = [...values];
    chars.forEach((ch, i) => { next[i] = ch; });
    setValues(next);
    focusInput(Math.min(chars.length, length - 1));

    if (chars.length === length) {
      onComplete?.(next.join(''));
    }
  }, [values, length, onComplete]);

  return (
    <div role="group" aria-label="OTP Input" onPaste={handlePaste}
         style={{ display: 'flex', gap: 8 }}>
      {values.map((val, i) => (
        <input
          key={i}
          ref={(el) => { inputRefs.current[i] = el; }}
          type="text"
          inputMode="numeric"
          autoComplete={i === 0 ? 'one-time-code' : 'off'}
          maxLength={1}
          value={val}
          onChange={(e) => handleChange(i, e)}
          onKeyDown={(e) => handleKeyDown(i, e)}
          aria-label={`Digit ${i + 1} of ${length}`}
          style={{
            width: 48, height: 56, textAlign: 'center',
            fontSize: 24, border: '2px solid #ccc', borderRadius: 8
          }}
        />
      ))}
    </div>
  );
}

// Usage
function VerifyPage() {
  const handleOTP = (otp) => {
    console.log('OTP entered:', otp);
    // POST /api/verify-otp { otp }
  };
  return (
    <div>
      <h2>Enter verification code</h2>
      <OTPInput length={6} onComplete={handleOTP} />
    </div>
  );
}

Real-World Applications

Use Cases

Two-Factor Authentication

Login flows where users enter a 6-digit code from an authenticator app or SMS.

Phone Number Verification

E-commerce and food delivery apps like Swiggy send SMS OTPs to verify phone numbers during registration.

Payment Confirmation

Banking and fintech apps require OTP entry to authorize transactions.

Mini Projects

OTP Verification Flow

intermediate

Build a complete OTP flow: phone input → send code → OTP entry with countdown timer → resend button → success screen.

Accessible OTP with Validation

intermediate

Extend the OTP component with error states, shake animation on wrong code, aria-live announcements, and automatic retry limiting.

Industry Examples

Swiggy

OTP input is a confirmed machine coding round question at Swiggy. Their login flow uses SMS OTP verification for 500+ city user base.

Razorpay

Payment gateway uses OTP inputs for 3D Secure card authentication with auto-read from SMS on mobile devices.

Resources

MDN - HTMLElement.focus()

docs

MDN - Clipboard API and paste events

docs

WAI-ARIA Practices - Managing Focus

docs

Related Questions

What is the difference between controlled and uncontrolled components in React forms?

mid
forms

How do you ensure accessibility (a11y) in React applications?

mid
accessibility
Previous
When should you use Context API vs Redux for state management?
Next
Build an autocomplete/typeahead search component in React that fetches suggestions from an API with debouncing, keyboard navigation, and highlighted matching text.
PrevNext