Official Solution
import React, { useMemo, useRef, useState } from 'react';
export default function App() {
const [digits, setDigits] = useState(['', '', '', '']);
const refs = useRef([]);
const code = useMemo(() => digits.join(''), [digits]);
function setAt(i, value) {
setDigits((prev) => {
const next = [...prev];
next[i] = value;
return next;
});
}
function onChange(i, e) {
const raw = e.target.value;
const nextDigit = raw.replace(/\\D/g, '').slice(-1);
setAt(i, nextDigit);
if (nextDigit && refs.current[i + 1]) refs.current[i + 1].focus();
}
function onKeyDown(i, e) {
if (e.key !== 'Backspace') return;
if (digits[i]) {
setAt(i, '');
return;
}
if (refs.current[i - 1]) refs.current[i - 1].focus();
}
function submit(e) {
e.preventDefault();
if (code.length !== 4) return;
alert('OTP submitted on meetcode: ' + code);
}
return (
<div style={{ padding: 16 }}>
<h2 style={{ marginTop: 0 }}>meetcode OTP</h2>
<form onSubmit={submit}>
<div style={{ display: 'flex', gap: 10 }}>
{digits.map((d, i) => (
<input
key={i}
ref={(el) => { refs.current[i] = el; }}
inputMode='numeric'
value={d}
onChange={(e) => onChange(i, e)}
onKeyDown={(e) => onKeyDown(i, e)}
style={{ width: 52, height: 52, textAlign: 'center', fontSize: 20, borderRadius: 14, border: '1px solid #bbb' }}
/>
))}
</div>
<button type='submit' disabled={code.length !== 4} style={{ marginTop: 12, padding: '10px 14px', borderRadius: 12, border: 0, background: '#0b5', color: '#fff', opacity: code.length === 4 ? 1 : 0.6 }}>Verify</button>
</form>
<div style={{ marginTop: 10, color: '#555' }}>Code: {code || '....'}</div>
</div>
);
}
No comments yet. Start the discussion!