Event Bubbling
Overview
When an event happens on an element (like a click on a <button>), it first runs the handlers on that button. Then, it 'bubbles' upwards to its parent (like a <div>), then to its grandparent, all the way up to the document root.
This behavior is called Event Bubbling. It allows for a powerful technique called 'Event Delegation', where you place a single listener on a parent element to handle events for all its children.
Syntax
const btn = document.querySelector('.btn');
btn.addEventListener('click', (e) => {
// e.stopPropagation() kills the bubble immediately!
// The event will not travel up to parent elements.
e.stopPropagation();
console.log("Button clicked!");
});// Instead of adding 100 listeners to 100 <li> items,
// we add ONE listener to the parent <ul>!
const list = document.querySelector('.todo-list');
list.addEventListener('click', (e) => {
// e.target is the exact element that was clicked
if (e.target.tagName === 'LI') {
e.target.classList.toggle('completed');
}
});Common Pitfalls
- Adding thousands of event listeners to a huge list of elements (e.g., rendering a table with 5,000 rows and adding a click listener to every row). This will massively spike memory usage and lag the browser. Always use Event Delegation for large lists.
Interview Questions
e.target and e.currentTarget?e.target is the exact element that originated the event (e.g., the specific text span inside the button you clicked). e.currentTarget is the element that the event listener is currently attached to (e.g., the parent form element catching the bubble).
Real-World Example
Closing a custom dropdown menu when the user clicks anywhere outside of it by utilizing bubbling to the document root.
document.addEventListener('click', (e) => {
if (!dropdownMenu.contains(e.target)) {
dropdownMenu.classList.remove('show');
}
});Check Your Knowledge
Test your understanding of Event Bubbling with these quick questions.