What is event bubbling and capturing?
When an event fires, it travels through the DOM in two phases.
Capturing phase — the event travels top-down, from the root down to the target element.
Bubbling phase — the event travels bottom-up, from the target back up to the root.
By default, listeners fire during the bubbling phase. To listen during capturing, pass true (or { capture: true }) as the third argument to addEventListener.
Good to know: stop the journey with event.stopPropagation(); bubbling is also what makes event delegation possible.
// HTML: <div id="outer"><div id="inner"><button>Click</button></div></div>
// Bubbling (default) — bottom-up
document.getElementById('outer').addEventListener('click', () => {
console.log('Outer clicked'); // Fires second (bubbling up)
});
document.getElementById('inner').addEventListener('click', () => {
console.log('Inner clicked'); // Fires first (closer to target)
});
// Click button: 'Inner clicked', 'Outer clicked'
// Capturing — top-down
document.getElementById('outer').addEventListener('click', () => {
console.log('Outer (capture)'); // Fires first (capturing down)
}, { capture: true });
document.getElementById('inner').addEventListener('click', () => {
console.log('Inner (capture)'); // Fires second
}, { capture: true });
// Click button: 'Outer (capture)', 'Inner (capture)'
// Stop propagation
document.getElementById('inner').addEventListener('click', (e) => {
e.stopPropagation(); // Outer handler will NOT fire
console.log('Inner only');
});
// Event delegation uses bubbling
document.getElementById('list').addEventListener('click', (e) => {
if (e.target.matches('.delete-btn')) {
deleteItem(e.target.closest('li').dataset.id);
}
});Bubbling: inner fires first, then outer (bottom-up). Capturing: outer fires first, then inner (top-down, needs {capture: true}). stopPropagation prevents the event from reaching outer.
Event delegation leverages bubbling — one listener on a parent handles all child clicks.
Know the three phases: capturing (down) → target → bubbling (up). Default is bubbling. stopPropagation stops travel.
Event delegation uses bubbling (one parent listener for many children). Capturing is rarely used but asked about.