Building an OTP Input Component in React
A step-by-step guide to creating a 5-digit OTP input with automatic focus management
✅ 1. Initial Setup and State Management
Start by importing essential React hooks and defining component state:
import { useEffect, useRef, useState } from "react"; const DIGIT_COUNT = 5; const [value, setValue] = useState(new Array(DIGIT_COUNT).fill("")); const refArr = useRef([]);
Then, inside the component App, you define:
- DIGIT_COUNT – how many OTP input boxes you want
- value – state array to store each digit
- refArr – a mutable array to store refs for input boxes
✅ 2. Initial Focus Management
Use useEffect to focus the first input on component mount:
useEffect(() => { refArr.current[0]?.focus(); }, []);
✅ 3. Input Change Handling
Implementation logic for handling input changes:
const handleOnChange = (val, index) => { val = val.trim(); const newArray = [...value]; newArray[index] = val.slice(-1); // Only last character setValue(newArray); val && refArr.current[index + 1]?.focus(); };
This ensures only the last digit is used when pasting multiple characters
You define handleOnChange to:
- Accept only the last character typed
- Update the state for the current index
- Automatically focus the next input box if there is input
✅ 4. Backspace Handling
Implement backward navigation for better UX:
const handleOnKeyDown = (e, index) => { if (!value[index] && e.key === "Backspace") { refArr.current[index - 1]?.focus(); } };
This improves UX for deleting digits quickly.
You define handleOnKeyDown to handle backward navigation:
- If the current input is empty and the user presses Backspace, move focus to the previous input
✅ 5. Rendering the OTP Boxes
{value.map((val, index) => { return ( <input className="box" key={index} type="number" value={value[index]} onChange={(e) => handleOnChange(e.target.value, index)} ref={(val) => (refArr.current[index] = val)} onKeyDown={(e) => handleOnKeyDown(e, index)} /> ); })}
You map over the value array and render an <input>
for each digit:
- Assign ref so you can control focus
- Limit input to one number
- Call the respective handlers for onChange and onKeyDown
✅ 6. Styling (Assumed from styles.css)
Each input is styled with the .box class to look uniform and user-friendly. A typical CSS for OTP boxes might look like:
.box { width: 40px; height: 40px; font-size: 24px; text-align: center; margin: 0 5px; }
✅ 7. Resulting Behavior
The final OTP input component:
- Renders 5 separate input boxes
- Focuses the first input on load
- Automatically moves focus as you type or backspace
- Accepts only 1 digit per box
- Provides a smooth user experience like most OTP inputs on modern apps
Key Features
- Automatic focus progression
- Single character validation
- Backspace navigation
- Paste handling