React Coding Questions with Solutions 2026, 25 Machine-Round Problems

What changed in 2026 drives
Mass-recruiter offer letters are flatter for 2026 batch - the 4-5 LPA ASE band has barely budged in three years while inflation eats real wages. Premium tracks (Digital, Pro, Elite, Specialist) are still where the differential lives, and they are entirely test-driven. If you are aiming higher than the default offer, the coding round is not optional pageantry - it is the entire interview.
What I'd actually study for this
- 01Two solid coding-round answers (1 medium-hard DSA each, with edge-case discussion) > five half-baked ones
- 02One real project you can defend end-to-end - file paths, design decisions, and what you would change
- 03One DBMS schema you actually built (not a textbook ER diagram), with at least 3 join-heavy queries written from memory
- 04Three behavioural STAR stories: failure recovered, conflict handled, ownership taken
Where most candidates trip up
The single biggest mistake is treating company-specific guides as primary prep and DSA as secondary. It is the opposite. Mass recruiters use the test as a filter, but premium tracks at every IT services company use coding to allocate offer band. Spend 70% of prep time on DSA + system fundamentals, 20% on company-specific patterns, 10% on HR rehearsal. Reverse that ratio and you collect the default offer.
Editorial commentary by Aditya Sharma · written for PapersAdda · not generated, not aggregated.
The React machine-coding round is where offers are won or lost. Candidates report that companies like Flipkart, Swiggy, Razorpay, and most funded startups have replaced trivia with a live build: 45 to 90 minutes, working app, explain as you go. This guide gives 25 real coding problems compiled from candidate-reported rounds and public preparation resources, each with a complete, runnable solution and the edge cases that decide the verdict.
How to use this: Build each one from scratch before reading the solution. The graders care that you can structure state and handle edge cases under time pressure, not that you memorized code.
Related: React Interview Questions 2026 | React Hooks Interview Questions 2026 | React Output Questions 2026 | React Redux Interview Questions 2026
Difficulty tiers at a glance
| Tier | Time budget | Examples | What is graded |
|---|---|---|---|
| Warm-up | 15 to 25 min | Counter, toggle, accordion | Controlled state, event handling |
| Core | 30 to 45 min | Debounced search, todo, star rating | State design, derived state, edge cases |
| Hard | 45 to 90 min | Infinite scroll, autocomplete, kanban | API handling, performance, accessibility |
Warm-up Problems (P1 to P6)
P1. Counter with step and reset
function Counter() {
const [count, setCount] = useState(0);
const [step, setStep] = useState(1);
return (
<div>
<button onClick={() => setCount(c => c - step)}>-</button>
<span>{count}</span>
<button onClick={() => setCount(c => c + step)}>+</button>
<input type="number" value={step} onChange={e => setStep(Number(e.target.value))} />
<button onClick={() => setCount(0)}>reset</button>
</div>
);
}
Gotcha: use the functional updater so rapid clicks do not drop increments.
P2. Toggle / show-hide
function Toggle({ children }) {
const [open, setOpen] = useState(false);
return (
<>
<button aria-expanded={open} onClick={() => setOpen(o => !o)}>
{open ? 'Hide' : 'Show'}
</button>
{open && <div>{children}</div>}
</>
);
}
Gotcha: add aria-expanded for accessibility points.
P3. Accordion (only one open)
function Accordion({ items }) {
const [openId, setOpenId] = useState(null);
return items.map(it => (
<div key={it.id}>
<button onClick={() => setOpenId(id => id === it.id ? null : it.id)}>{it.title}</button>
{openId === it.id && <p>{it.body}</p>}
</div>
));
}
P4. Controlled form with validation
function SignupForm() {
const [email, setEmail] = useState('');
const valid = /^[^@]+@[^@]+\.[^@]+$/.test(email);
return (
<form onSubmit={e => { e.preventDefault(); if (valid) submit(email); }}>
<input value={email} onChange={e => setEmail(e.target.value)} />
{!valid && email && <span>Invalid email</span>}
<button disabled={!valid}>Submit</button>
</form>
);
}
P5. Tabs
function Tabs({ tabs }) {
const [active, setActive] = useState(0);
return (
<div>
<div role="tablist">
{tabs.map((t, i) => (
<button key={i} role="tab" aria-selected={i === active} onClick={() => setActive(i)}>{t.label}</button>
))}
</div>
<div role="tabpanel">{tabs[active].content}</div>
</div>
);
}
P6. Stopwatch
function Stopwatch() {
const [ms, setMs] = useState(0);
const [running, setRunning] = useState(false);
useEffect(() => {
if (!running) return;
const start = Date.now() - ms;
const id = setInterval(() => setMs(Date.now() - start), 50);
return () => clearInterval(id);
}, [running]);
return (
<div>
<span>{(ms / 1000).toFixed(2)}s</span>
<button onClick={() => setRunning(r => !r)}>{running ? 'Pause' : 'Start'}</button>
<button onClick={() => { setMs(0); setRunning(false); }}>Reset</button>
</div>
);
}
Gotcha: compute elapsed from a fixed start so pause/resume stays accurate; do not accumulate in the interval.
Core Problems (P7 to P16)
P7. Debounced search with cancellation
function useDebounce(value, delay = 300) {
const [d, setD] = useState(value);
useEffect(() => {
const id = setTimeout(() => setD(value), delay);
return () => clearTimeout(id);
}, [value, delay]);
return d;
}
function Search() {
const [q, setQ] = useState('');
const dq = useDebounce(q);
const [results, setResults] = useState([]);
useEffect(() => {
if (!dq) return setResults([]);
const ctrl = new AbortController();
fetch(`/api/search?q=${dq}`, { signal: ctrl.signal })
.then(r => r.json()).then(setResults)
.catch(e => { if (e.name !== 'AbortError') console.error(e); });
return () => ctrl.abort();
}, [dq]);
return (
<>
<input value={q} onChange={e => setQ(e.target.value)} />
<ul>{results.map(r => <li key={r.id}>{r.name}</li>)}</ul>
</>
);
}
Gotcha: without AbortController a slow earlier response can overwrite a newer one (race condition). Interviewers probe this directly.
P8. Todo app with useReducer
function reducer(state, a) {
switch (a.type) {
case 'add': return [...state, { id: Date.now(), text: a.text, done: false }];
case 'toggle': return state.map(t => t.id === a.id ? { ...t, done: !t.done } : t);
case 'remove': return state.filter(t => t.id !== a.id);
default: return state;
}
}
function Todos() {
const [todos, dispatch] = useReducer(reducer, []);
const [text, setText] = useState('');
return (
<div>
<input value={text} onChange={e => setText(e.target.value)} />
<button onClick={() => { dispatch({ type: 'add', text }); setText(''); }}>Add</button>
{todos.map(t => (
<div key={t.id}>
<input type="checkbox" checked={t.done} onChange={() => dispatch({ type: 'toggle', id: t.id })} />
<span style={{ textDecoration: t.done ? 'line-through' : 'none' }}>{t.text}</span>
<button onClick={() => dispatch({ type: 'remove', id: t.id })}>x</button>
</div>
))}
</div>
);
}
P9. Star rating
function Stars({ max = 5, value, onChange }) {
const [hover, setHover] = useState(0);
return [...Array(max)].map((_, i) => {
const n = i + 1;
return (
<span key={n} onMouseEnter={() => setHover(n)} onMouseLeave={() => setHover(0)}
onClick={() => onChange(n)} style={{ cursor: 'pointer' }}>
{n <= (hover || value) ? '★' : '☆'}
</span>
);
});
}
P10. Pagination
function usePagination(items, perPage = 10) {
const [page, setPage] = useState(1);
const pages = Math.ceil(items.length / perPage);
const slice = items.slice((page - 1) * perPage, page * perPage);
return { page, pages, slice, setPage };
}
P11. Modal with focus trap and Escape
function Modal({ onClose, children }) {
const ref = useRef(null);
useEffect(() => {
const onKey = e => e.key === 'Escape' && onClose();
document.addEventListener('keydown', onKey);
ref.current?.focus();
return () => document.removeEventListener('keydown', onKey);
}, [onClose]);
return (
<div role="dialog" aria-modal="true" tabIndex={-1} ref={ref}
onClick={e => e.target === e.currentTarget && onClose()}>
<div className="content">{children}</div>
</div>
);
}
Gotcha: close on backdrop click only when the target is the backdrop, not bubbled child clicks.
P12. Light/dark theme toggle with persistence
function useTheme() {
const [theme, setTheme] = useState(() => localStorage.getItem('theme') || 'light');
useEffect(() => {
document.documentElement.dataset.theme = theme;
localStorage.setItem('theme', theme);
}, [theme]);
return [theme, () => setTheme(t => t === 'light' ? 'dark' : 'light')];
}
P13. OTP input (auto-advance)
function OtpInput({ length = 6, onComplete }) {
const [vals, setVals] = useState(Array(length).fill(''));
const refs = useRef([]);
const set = (i, v) => {
if (!/^\d?$/.test(v)) return;
const next = [...vals]; next[i] = v; setVals(next);
if (v && i < length - 1) refs.current[i + 1].focus();
if (next.every(Boolean)) onComplete(next.join(''));
};
return vals.map((v, i) => (
<input key={i} ref={el => refs.current[i] = el} value={v} maxLength={1}
onChange={e => set(i, e.target.value)} />
));
}
P14. Countdown timer
function Countdown({ seconds }) {
const [left, setLeft] = useState(seconds);
useEffect(() => {
if (left <= 0) return;
const id = setTimeout(() => setLeft(l => l - 1), 1000);
return () => clearTimeout(id);
}, [left]);
return <span>{left}s</span>;
}
P15. Editable table cell
function Cell({ value, onSave }) {
const [edit, setEdit] = useState(false);
const [draft, setDraft] = useState(value);
return edit ? (
<input autoFocus value={draft} onChange={e => setDraft(e.target.value)}
onBlur={() => { onSave(draft); setEdit(false); }} />
) : <span onClick={() => setEdit(true)}>{value}</span>;
}
P16. Multi-select with chips
function MultiSelect({ options }) {
const [selected, setSelected] = useState([]);
const toggle = o => setSelected(s => s.includes(o) ? s.filter(x => x !== o) : [...s, o]);
return (
<div>
<div>{selected.map(s => <span key={s} onClick={() => toggle(s)}>{s} x</span>)}</div>
{options.map(o => <button key={o} disabled={selected.includes(o)} onClick={() => toggle(o)}>{o}</button>)}
</div>
);
}
Hard Problems (P17 to P25)
P17. Infinite scroll with IntersectionObserver
function InfiniteList({ fetchPage }) {
const [items, setItems] = useState([]);
const [page, setPage] = useState(1);
const sentinel = useRef(null);
useEffect(() => { fetchPage(page).then(p => setItems(prev => [...prev, ...p])); }, [page]);
useEffect(() => {
const obs = new IntersectionObserver(([e]) => e.isIntersecting && setPage(p => p + 1));
if (sentinel.current) obs.observe(sentinel.current);
return () => obs.disconnect();
}, []);
return (<>{items.map(i => <div key={i.id}>{i.name}</div>)}<div ref={sentinel} /></>);
}
Gotcha: debounce or guard against double-firing while a page is still loading.
P18. Autocomplete with keyboard navigation
Combine the debounced fetch from P7 with arrow-key index state and Enter to select; expose role="listbox" and aria-activedescendant. Candidate-reported as the most common hard machine-coding task.
function Autocomplete({ fetchOptions }) {
const [q, setQ] = useState('');
const dq = useDebounce(q);
const [opts, setOpts] = useState([]);
const [active, setActive] = useState(-1);
useEffect(() => {
if (!dq) return setOpts([]);
const ctrl = new AbortController();
fetchOptions(dq, ctrl.signal).then(setOpts).catch(() => {});
return () => ctrl.abort();
}, [dq]);
const onKey = (e) => {
if (e.key === 'ArrowDown') setActive(a => Math.min(a + 1, opts.length - 1));
if (e.key === 'ArrowUp') setActive(a => Math.max(a - 1, 0));
if (e.key === 'Enter' && active >= 0) setQ(opts[active].label);
};
return (
<div>
<input value={q} onKeyDown={onKey} onChange={e => setQ(e.target.value)}
role="combobox" aria-expanded={opts.length > 0} aria-activedescendant={`opt-${active}`} />
<ul role="listbox">
{opts.map((o, i) => (
<li id={`opt-${i}`} key={o.id} role="option" aria-selected={i === active}>{o.label}</li>
))}
</ul>
</div>
);
}
The grading checklist here is dense: debounce to limit requests, cancellation for race safety, keyboard navigation with clamping at both ends, and ARIA roles for accessibility. Candidates report that nailing the keyboard plus ARIA combination is what separates a pass from a partial. A common follow-up asks you to highlight the matched substring, which you handle by splitting the label on the query and wrapping the match in a <mark>.
P19. Drag-and-drop reorder
Track the dragged index and the hovered index; on drop, splice the array immutably. Use the HTML5 drag events or pointer events. Grade points come from keyboard-accessible reordering.
function Reorder({ initial }) {
const [items, setItems] = useState(initial);
const dragIdx = useRef(null);
const onDrop = (to) => {
const from = dragIdx.current;
if (from === null || from === to) return;
setItems(list => {
const copy = [...list];
const [moved] = copy.splice(from, 1);
copy.splice(to, 0, moved);
return copy;
});
};
return items.map((it, i) => (
<div key={it.id} draggable
onDragStart={() => (dragIdx.current = i)}
onDragOver={e => e.preventDefault()}
onDrop={() => onDrop(i)}>
{it.label}
</div>
));
}
The immutable splice (copy, remove, insert) is the core; mutating items in place would skip the re-render. Senior rounds expect a keyboard path too: select an item with Enter, move it with arrow keys, and drop with Enter again, since pointer-only reordering fails accessibility audits.
P20. Nested comments (recursive component)
function Comment({ node }) {
return (
<div style={{ marginLeft: 16 }}>
<p>{node.text}</p>
{node.children?.map(c => <Comment key={c.id} node={c} />)}
</div>
);
}
P21. Virtualized list (windowing) basics
Render only the rows in the visible viewport plus an overscan buffer, computing startIndex from scrollTop / rowHeight. This is the performance-credibility question for large lists.
function VirtualList({ rows, rowHeight = 40, height = 400 }) {
const [scrollTop, setScrollTop] = useState(0);
const overscan = 5;
const start = Math.max(0, Math.floor(scrollTop / rowHeight) - overscan);
const visible = Math.ceil(height / rowHeight) + overscan * 2;
const slice = rows.slice(start, start + visible);
return (
<div style={{ height, overflow: 'auto' }} onScroll={e => setScrollTop(e.currentTarget.scrollTop)}>
<div style={{ height: rows.length * rowHeight, position: 'relative' }}>
{slice.map((r, i) => (
<div key={start + i} style={{ position: 'absolute', top: (start + i) * rowHeight, height: rowHeight }}>
{r.label}
</div>
))}
</div>
</div>
);
}
The trick is the spacer div sized to the full list height so the scrollbar reflects the real total, while only a window of rows mounts. Candidates report interviewers ask why this beats rendering 10,000 nodes: the DOM node count stays constant regardless of list size, so scroll stays smooth and memory stays flat.
P22. Form wizard (multi-step with shared state)
Lift the form data to a parent, render the active step, and validate per step before advancing. Use useReducer for the aggregate state. The parent owns one state object; each step is a controlled view over its slice and reports validity up before the Next button enables. Keeping all step data in one place lets you submit the whole payload at the end and lets users navigate back without losing input.
P23. Poll / live data with cleanup
useEffect(() => {
const id = setInterval(() => fetch('/api/status').then(r => r.json()).then(setStatus), 5000);
return () => clearInterval(id);
}, []);
P24. Undo/redo
Keep three stacks: past, present, future. On change push present to past; undo pops past to future; redo reverses. A reducer makes this clean and testable.
P25. Kanban board
Compose drag-and-drop (P19), columns with arrays, and immutable moves between columns. The senior-level capstone; grade points for clean state shape and accessibility.
React Coding Mock Test, 2026 Edition
5 original questions calibrated to the 2026 React coding batch by Aditya Sharma, from candidate-reported round patterns.
Question 1
In a debounced search, what bug appears without request cancellation?
a) Memory leak only b) A slower earlier response overwrites a newer one c) Nothing d) Infinite loop
Solution: Out-of-order responses cause stale results; use AbortController or a request-id guard. Answer: (b)
Question 2
Which hook centralizes interrelated state transitions for a todo app?
a) useRef b) useReducer c) useMemo d) useId
Solution: useReducer keeps transitions in one pure function. Answer: (b)
Question 3
For infinite scroll, the idiomatic 2026 trigger is:
a) scroll event listener b) IntersectionObserver on a sentinel c) setInterval d) resize observer
Solution: IntersectionObserver is efficient and avoids scroll thrash. Answer: (b)
Question 4
A modal should close on backdrop click only when:
a) any click b) the click target equals the backdrop element c) Escape only d) never
Solution: Compare e.target === e.currentTarget to ignore bubbled child clicks. Answer: (b)
Question 5
The standard data structure for undo/redo is:
a) single array b) past/present/future stacks c) linked list only d) a Map
Solution: Three stacks make undo and redo O(1) and testable. Answer: (b)
FAQ, React Coding Round Questions
Q: Should I style my coding-round solution? Minimal styling is fine. Candidates report functionality and clean state design outweigh CSS; add basic accessibility for bonus points.
Q: Can I use a library in the coding round? Confirm with the interviewer. Many candidate-reported rounds want vanilla React to see your fundamentals; some allow React Query or a UI kit.
Q: How do I handle running out of time? State your plan, ship a working core, and verbally describe the remaining edge cases. A partially complete but explained solution scores better than a broken full attempt.
Q: Do they test TypeScript? Increasingly yes at product companies. Confirm the stack on the official company careers page when you get the invite.
You May Also Like
Methodology applied to this articlelast verified 8 Jun 2026
- No fabricated salary numbers or success rates. If we quote a range, it's sourced.
- No noun-substituted templates. This article was not generated by swapping company names in a stock prompt.
- No paid placements, sponsored coaching links, or affiliate-shilled course pushes.
Explore this topic cluster
More resources in Interview Questions
Use the category hub to browse similar questions, exam patterns, salary guides, and preparation resources related to this topic.
Paid contributor programme
Sat this this year? Share your story, earn ₹500.
First-person experience reports help future candidates prep smarter. We pay verified contributors ₹500 via UPI per accepted story - with byline.
Submit your story →Ready to practice?
Take a free timed mock test
Put what you learned into practice. Our mock tests match the 2026 pattern with timer, navigator, reveal, and score breakdown. No signup.
Start Free Mock Test →More from PapersAdda
Adobe Coding Round Questions 2026: Patterns + Solutions
Amazon Coding Round Questions 2026: Patterns + Solutions
Uber Coding Round Questions 2026: Patterns + Solutions
Coforge Interview Process 2026: Round-by-Round Guide