issue 117apr 27mmxxvi
est. 2017
Sun, 27 Apr 2026
vol. IX · no. 117
PapersAdda
placement intelligence, since 2017
640+ briefs · 24 campuses · by reservation
verified offers · sourced from r/developersIndia
razorpay₹65.00 LPA· iit-d · sde-1google₹54.00 LPA· iiit-h · swe-imicrosoft₹49.50 LPA· iit-b · sdeatlassian₹38.00 LPA· nit-w · sde-1amazon₹44.20 LPA· bits-p · sde-1uber₹42.00 LPA· iit-kgp · sde-1razorpay₹65.00 LPA· iit-d · sde-1google₹54.00 LPA· iiit-h · swe-imicrosoft₹49.50 LPA· iit-b · sdeatlassian₹38.00 LPA· nit-w · sde-1amazon₹44.20 LPA· bits-p · sde-1uber₹42.00 LPA· iit-kgp · sde-1

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

13 min read
Interview Questions
Updated: 8 Jun 2026
Aditya Sharma
Aditya's Edit

PapersAdda 2026 Placement Cycle

By Aditya Sharma·Founder & Editor, PapersAdda

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

TierTime budgetExamplesWhat is graded
Warm-up15 to 25 minCounter, toggle, accordionControlled state, event handling
Core30 to 45 minDebounced search, todo, star ratingState design, derived state, edge cases
Hard45 to 90 minInfinite scroll, autocomplete, kanbanAPI 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
Sources used
Public exam-pattern documents, official recruiter pages, and verified candidate reports on r/developersIndia and LinkedIn.
Verification window
Page last edited 8 Jun 2026 by Aditya Sharma. Numbers and patterns sanity-checked against the most recent 2026 cycle drives we tracked.
What we did NOT do
  • 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.
Verification policy: /editorial-standards/. Found something incorrect? Submit a correction - we respond within 48 hours.

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

Share this guide: