Explain event delegation, capturing, and bubbling in the browser
Three phases of event propagation
When you click a DOM element, the event travels in three phases — it doesn't just fire on that one element.
Window
└─ Document
└─ <html>
└─ <body>
└─ <div> ← 1. Capture phase (top → target)
└─ <button> ← 2. Target phase
└─ <div> ← 3. Bubble phase (target → top)
1. Capture phase
The event travels down from window to the target. Pass true as the third argument to addEventListener to listen in this phase.
parent.addEventListener('click', handler, true); // capture
2. Target phase
The event reaches the element that was actually clicked. Both capture and bubble listeners on this element run.
3. Bubble phase
The event travels back up from the target to window. This is the default phase for addEventListener.
child.addEventListener('click', handler); // bubble (default)
child.addEventListener('click', handler, false); // same
Not all events bubble:
focus,blur,load,scrolldo not bubble by default.
Stopping propagation
e.stopPropagation()— stops the event from travelling further up (or down).e.stopImmediatePropagation()— stops propagation and also prevents any remaining listeners on the same element.
child.addEventListener('click', (e) => {
e.stopPropagation(); // parent won't receive the event
});
Event delegation
Because events bubble, you can attach a single listener on a parent to handle events from all its children.
Benefits
- Fewer event listeners → less memory
- Dynamically added children are automatically covered — no need to re-bind
Example
<ul id="list">
<li>item 1</li>
<li>item 2</li>
<li>item 3</li>
</ul>
// Avoid: binding to every <li>
document.querySelectorAll('#list li').forEach(li => {
li.addEventListener('click', handleClick);
});
// Better: delegate to the parent
document.getElementById('list').addEventListener('click', (e) => {
if (e.target.tagName === 'LI') {
console.log('Clicked:', e.target.textContent);
}
});
Preventing default behaviour
e.preventDefault() cancels the browser's built-in reaction (e.g. following a link, submitting a form). This is separate from stopping propagation.
Summary
| Concept | Direction | How to listen |
|---|---|---|
| Capture | window → target | addEventListener(_, _, true) |
| Target | — | Both phases fire |
| Bubble | target → window | addEventListener(_, _) (default) |
| Delegation | Use bubbling to handle children on a parent | — |
✦ AI Mock Interview
Type your answer and get instant AI feedback
Sign in to use AI scoring
