ReactEvent Handlingintermediate
Updated:

React Event Handling Interview Questions and Answers

6 min read

The event handling questions React interviews ask — synthetic events, passing arguments to handlers, preventDefault, delegation and handler performance.

TL;DR – Quick Answer

React event-handling interviews test the synthetic event system: how React wraps native events in a cross-browser SyntheticEvent, why handlers use camelCase and receive a function reference not a call, how to pass arguments, preventDefault and stopPropagation, and how React attaches listeners at the root rather than per element. Interviewers also probe practical points — passing arguments without creating a new function every render, and handling keyboard and form events correctly.

On This Page

Event handling looks simple until an interviewer probes the synthetic event system, argument passing, or why a handler fired at the wrong time. The questions below cover how React normalizes events, the reference-versus-call trap that catches beginners, preventDefault and stopPropagation, React's delegation model, and the small performance points around creating handlers. Ground your answers in "React wraps native events and delegates them from the root" and the rest follows.

How to answer event-handling questions

Two ideas cover most questions: React passes your JSX handler a SyntheticEvent — a cross-browser wrapper around the native event — and you give the prop a function reference, not a call. From there, argument passing, preventDefault, and delegation are natural extensions. When a "why did this fire wrong" question comes up, it is almost always a reference-versus-call or a bubbling issue; name which and you have the answer.

Q1. What is a SyntheticEvent?

A SyntheticEvent is React's cross-browser wrapper around the native DOM event. It exposes the same interface (target, type, preventDefault, stopPropagation) but normalizes differences between browsers, so a handler behaves identically everywhere. The underlying native event is available via event.nativeEvent when you need it.

The value is consistency: you write one handler and React smooths over browser quirks. It also plugs into React's own dispatch system rather than relying on raw DOM listeners scattered across elements.

Interview note: Follow-up: "is event pooling still a thing?" React used to pool and reuse synthetic event objects (requiring e.persist() for async access), but that pooling was removed in React 17. In current React you can read the event asynchronously without persist().

Q2. Why do you pass a reference, not a call, to an event prop?

onClick={handleClick} passes the function so React calls it when the event fires. onClick={handleClick()} calls it during render and passes the return value — usually undefined — so it fires immediately and not on click. To pass arguments, wrap it: onClick={() => handleClick(id)}.

<button onClick={handleClick}>Fires on click</button>
<button onClick={handleClick()}>Runs on render — bug</button>
<button onClick={() => handleClick(id)}>Fires on click, with arg</button>

Interview note: Trap: "my handler runs on every render and I never clicked — why?" You wrote onClick={handleClick()}, invoking it during render. Remove the parentheses or wrap it in an arrow.

Q3. How do you pass arguments to an event handler?

Wrap the handler in an inline arrow function that calls it with the argument — onChange={(e) => handleField(name, e.target.value)} — or curry the handler so it returns a function. The arrow form is the clearest and most common; both preserve access to the event if you forward it.

{items.map(item => (
  <li key={item.id} onClick={() => onSelect(item.id)}>{item.name}</li>
))}

Interview note: Follow-up: "does the inline arrow hurt performance?" It creates a new function each render, which only matters if the child is wrapped in React.memo and relies on a stable prop — then use useCallback or restructure. For plain DOM elements it is negligible.

Q4. What do preventDefault and stopPropagation do?

preventDefault() cancels the browser's default action for the event — stopping a form from reloading the page, a link from navigating, a checkbox from toggling. stopPropagation() stops the event from bubbling up to ancestor handlers. They are independent: you often call one without the other.

function onSubmit(e) {
  e.preventDefault();   // stop the native form reload
  save();
}
function onInnerClick(e) {
  e.stopPropagation();  // don't trigger the parent's onClick
}

Interview note: Trap: "you called stopPropagation to stop a form reload — did it work?" No — bubbling and default actions are different. Stopping propagation does not prevent the default submit; you need preventDefault.

Q5. How does React attach event listeners under the hood?

React uses event delegation. Rather than attaching a listener to every element, it attaches one listener per event type at the root container (the app root in React 17+, previously document) and routes each event to the correct component handler by walking its internal tree. This reduces memory and setup cost, especially for large or dynamic lists.

The practical implication: your onClick on a list item is not a real DOM listener on that <li>; React captured the event at the root and dispatched it. This is why mixing React handlers with manually attached native listeners can behave unexpectedly.

Interview note: Follow-up: "where does React attach the root listener now?" Since React 17 it attaches to the root DOM container you render into, not document — which lets multiple React versions or apps coexist on one page without event conflicts.

Q6. How do the SyntheticEvent and native event interact with bubbling?

React's synthetic events follow the same capture-and-bubble model as native events, but they are dispatched by React's system from the root. If you mix a native listener (via a ref and addEventListener) with React handlers, ordering can surprise you because React's dispatch happens at the root, potentially after a native listener on a child. Knowing this boundary is a strong signal.

Interview note: Trap: "your native addEventListener handler ran before your React onClick — why?" The native listener fires during the real DOM bubble on that element; React's synthetic handler fires when the event reaches the root. Prefer React handlers unless you specifically need the native one.

Q7. How do you handle keyboard events and accessibility?

Use onKeyDown/onKeyUp and check event.key (e.g. "Enter", "Escape", "ArrowDown") rather than deprecated key codes. For accessibility, ensure interactive custom elements are focusable and respond to keyboard as well as click — a <div> acting as a button needs tabIndex, a role, and key handling, whereas a real <button> gives you all of that for free.

function onKeyDown(e) {
  if (e.key === "Enter" || e.key === " ") { e.preventDefault(); activate(); }
}

Interview note: Follow-up: "why prefer a real <button> over a clickable <div>?" The button is focusable, keyboard-activatable and announced correctly by screen readers by default; the div needs role, tabIndex and manual key handling to match.

Q8. What are common event-handling mistakes interviewers watch for?

Calling the handler instead of passing it (onClick={fn()}), forgetting preventDefault on form submit, confusing stopPropagation with preventDefault, creating handlers that capture stale state (a stale closure), and adding native listeners without cleanup. Each is a small bug that reveals whether you understand the model or copied a pattern.

Interview note: Trap: "your click handler logs an old value of state — why?" Stale closure: the handler captured state from an earlier render. Use the functional updater, keep dependencies honest, or store the latest value in a ref.

Q9. How do you optimize event handlers in performance-sensitive components?

Most handlers need no optimization. When a handler is passed to a memoized child, wrap it in useCallback so the child does not re-render on a new reference; when a handler must not fire too often (scroll, resize, live search), debounce or throttle it. Otherwise, inline arrow handlers are fine. The performance optimization set covers when reference stability actually matters.

const onSelect = useCallback((id) => dispatch(select(id)), [dispatch]);
// Stable reference — a React.memo child won't re-render because of this prop

Interview note: Follow-up: "you wrapped the handler in useCallback but the child still re-renders — why?" The child is not memoized, or another prop changes each render. useCallback only helps a React.memo child whose other props are also stable.

How to prepare

Wire up a small interactive component — a list where each row passes its id to a handler, a form with onSubmit and preventDefault, and a keyboard-accessible custom control — and deliberately trigger the classic bugs: the immediate-fire from fn(), the stale-closure log, the stopPropagation-instead-of-preventDefault mix-up. Fixing each once makes the concept stick. Rehearse the SyntheticEvent and delegation explanations, since those are the "do you understand the model" questions. Pair this with the forms handling set (submission and change events overlap heavily) and the components and props foundation, refresh details in the React learning path, and use a mock interview to practise the reference-versus-call and bubbling follow-ups out loud.

Frequently Asked Questions

What is a synthetic event in React?
A SyntheticEvent is React's cross-browser wrapper around the native DOM event. It normalizes behavior across browsers and exposes the same interface, so your handlers work consistently. You can still reach the underlying native event via event.nativeEvent.
How do you pass an argument to an event handler?
Wrap the handler in an arrow function that calls it with the argument, like onClick={() => handleDelete(id)}, or use a curried handler. The arrow form is clearest; be aware it creates a new function each render, which only matters for memoized children.
Why is my onClick firing immediately on render?
You passed a function call instead of a reference, like onClick={handleClick()} which runs during render. Pass the reference onClick={handleClick}, or wrap it: onClick={() => handleClick(arg)}.
How does React attach event listeners?
React uses event delegation: instead of attaching a listener to every element, it attaches one listener per event type at the root container and dispatches events to the right handler. This is more memory-efficient than per-element listeners.
How do preventDefault and stopPropagation differ?
preventDefault stops the browser's default action, like a form submitting or a link navigating. stopPropagation stops the event from bubbling up to parent handlers. They solve different problems and are often used independently.

Want to Build Your Career in Java Full Stack with AI?

Join CodeBegun and train with working industry engineers — Explore the Java Full Stack program

Apply for Demo Class →
Siva Prasad Galaba
Founder, CodeBegun · Staff Engineer

Founder of CodeBegun. 15+ years building Java systems at companies like Crunchyroll. Teaches Java, Spring Boot and system design the way the industry actually works, and mentors students through projects, mock interviews and placement preparation.

Technically reviewed by CodeBegun Technical TeamLast reviewed 16 July 2026 LinkedIn
Chat with us