Introductions
Event bubbling, event capturing, and event delegation are important JavaScript concepts for handling events efficiently. They become especially useful when one element is inside another element, such as buttons inside a card or list items inside a list. In this chapter, you will practice these concepts with simple examples and gradually move toward practical DOM interactions. JavaScript Event Bubbling, Capturing and Delegation practice questions with solutions help to understand the concepts.
Question 1: Understand Event Bubbling
Problem
Create a parent <div> containing a button. Add click events to both elements and observe which event runs first when the button is clicked.
Solution
<div id="parent">
<button id="button">Click Me</button>
</div>
<script>
const parent = document.getElementById("parent");
const button = document.getElementById("button");
parent.addEventListener("click", function() {
console.log("Parent clicked");
});
button.addEventListener("click", function() {
console.log("Button clicked");
});
</script>
Output
When the button is clicked:
Button clicked
Parent clicked
Step-by-step Explanation
- The button is inside the parent
<div>. - A click first happens on the button.
- The button’s event handler runs.
- The event then bubbles upward.
- The parent’s click handler runs.
- This upward movement is called event bubbling.
Question 2: Stop Event Bubbling
Problem
Create a parent and child button. Make sure clicking the button does not trigger the parent’s click event.
Solution
<div id="parent">
<button id="button">Click Me</button>
</div>
<script>
const parent = document.getElementById("parent");
const button = document.getElementById("button");
parent.addEventListener("click", function() {
console.log("Parent clicked");
});
button.addEventListener("click", function(event) {
event.stopPropagation();
console.log("Button clicked");
});
</script>
Output
When the button is clicked:
Button clicked
The parent message does not appear.
Step-by-step Explanation
- Normally, the button click would bubble to the parent.
event.stopPropagation()stops that propagation.- The button’s handler still runs.
- The parent’s handler does not run.
Question 3: Use Event Capturing
Problem
Create a parent and child element. Use event capturing on the parent and observe the order in which the events run.
Solution
<div id="parent">
<button id="button">Click Me</button>
</div>
<script>
const parent = document.getElementById("parent");
const button = document.getElementById("button");
parent.addEventListener("click", function() {
console.log("Parent event");
}, true);
button.addEventListener("click", function() {
console.log("Button event");
});
</script>
Output
When the button is clicked:
Parent event
Button event
Step-by-step Explanation
- The parent listener uses
trueas the third argument. - This enables event capturing.
- During capturing, the event travels from the outer element toward the target.
- The parent handler runs first.
- The button handler then runs.
Question 4: Compare Bubbling and Capturing
Problem
Create a three-level structure: outer box, middle box, and button. Add event listeners using both bubbling and capturing.
Solution
<div id="outer">
<div id="middle">
<button id="button">Click Me</button>
</div>
</div>
<script>
const outer = document.getElementById("outer");
const middle = document.getElementById("middle");
const button = document.getElementById("button");
outer.addEventListener("click", function() {
console.log("Outer");
}, true);
middle.addEventListener("click", function() {
console.log("Middle");
}, true);
button.addEventListener("click", function() {
console.log("Button");
});
middle.addEventListener("click", function() {
console.log("Middle bubbling");
});
</script>
Output
When the button is clicked, the capturing handlers run while the event travels toward the button, followed by the target and then bubbling handlers.
A simplified order is:
Outer
Middle
Button
Middle bubbling
Step-by-step Explanation
- The event starts outside the target.
- It travels downward during the capturing phase.
- The button becomes the target.
- After reaching the target, the event can travel upward.
- This upward phase is bubbling.
- Capturing and bubbling are two different phases of event propagation.
Question 5: Find the Actual Clicked Element with event.target
Problem
Create a list containing three items. Display the text of the item that the user clicks.
Solution
<ul id="list">
<li>HTML</li>
<li>CSS</li>
<li>JavaScript</li>
</ul>
<p id="result"></p>
<script>
const list = document.getElementById("list");
const result = document.getElementById("result");
list.addEventListener("click", function(event) {
result.textContent =
"You clicked: " + event.target.textContent;
});
</script>
Output
If the user clicks JavaScript:
You clicked: JavaScript
Step-by-step Explanation
- The click listener is attached to the
<ul>. - The click bubbles from the
<li>to the<ul>. event.targetidentifies the element where the event actually started.- Its
textContentis displayed. - This idea is very useful for event delegation.
Question 6: Basic Event Delegation
Problem
Create a list with three buttons. Instead of adding a separate click listener to every button, use one listener on the parent list.
Solution
<ul id="menu">
<li><button>Home</button></li>
<li><button>About</button></li>
<li><button>Contact</button></li>
</ul>
<script>
const menu = document.getElementById("menu");
menu.addEventListener("click", function(event) {
if (event.target.tagName === "BUTTON") {
console.log("Clicked:", event.target.textContent);
}
});
</script>
Output
Clicking Home:
Clicked: Home
Clicking Contact:
Clicked: Contact
Step-by-step Explanation
- There are three buttons.
- Only one event listener is attached to the
<ul>. - Button clicks bubble to the
<ul>. event.targetidentifies the clicked button.tagNamechecks whether the clicked element is a button.- This technique is called event delegation.
Question 7: Use closest() with Event Delegation
Problem
Create buttons containing <span> elements. Make sure clicking either the button or its text still identifies the correct button.
Solution
<div id="buttons">
<button>
<span>Home</span>
</button>
<button>
<span>About</span>
</button>
<button>
<span>Contact</span>
</button>
</div>
<p id="result"></p>
<script>
const buttons = document.getElementById("buttons");
const result = document.getElementById("result");
buttons.addEventListener("click", function(event) {
const button = event.target.closest("button");
if (button) {
result.textContent =
"Selected: " + button.textContent.trim();
}
});
</script>
Output
Clicking the text inside the About button:
Selected: About
Step-by-step Explanation
- The event may target the
<span>rather than the button. closest("button")searches upward from the clicked element.- It finds the nearest button.
- The button’s text is displayed.
- This is useful when delegated elements contain nested elements.
Question 8: Add Dynamic Elements with Event Delegation
Problem
Create a button that adds new list items. Use event delegation so newly created list items can also respond to clicks.
Solution
<button id="addButton">Add Item</button>
<ul id="list"></ul>
<script>
const addButton = document.getElementById("addButton");
const list = document.getElementById("list");
let count = 1;
addButton.addEventListener("click", function() {
const item = document.createElement("li");
item.textContent = "Item " + count;
list.appendChild(item);
count++;
});
list.addEventListener("click", function(event) {
if (event.target.tagName === "LI") {
event.target.style.fontWeight = "bold";
}
});
</script>
Output
After clicking Add Item three times:
Item 1
Item 2
Item 3
Clicking Item 2 makes it bold.
Step-by-step Explanation
- The Add Item button creates new
<li>elements. - The list has only one click listener.
- Newly created items automatically participate in event delegation.
event.targetidentifies the clicked list item.- The clicked item’s style is changed.
- No new event listener needs to be added to every new item.
Question 9: Remove Items Using Event Delegation
Problem
Create a list where every item contains a Remove button. Use one event listener on the parent list to remove the clicked item.
Solution
<ul id="taskList">
<li>
Learn HTML
<button class="remove">Remove</button>
</li>
<li>
Learn CSS
<button class="remove">Remove</button>
</li>
<li>
Learn JavaScript
<button class="remove">Remove</button>
</li>
</ul>
<script>
const taskList = document.getElementById("taskList");
taskList.addEventListener("click", function(event) {
if (event.target.classList.contains("remove")) {
const item = event.target.closest("li");
item.remove();
}
});
</script>
Output
Initially:
Learn HTML [Remove]
Learn CSS [Remove]
Learn JavaScript [Remove]
If the user clicks Remove next to CSS:
Learn HTML [Remove]
Learn JavaScript [Remove]
Step-by-step Explanation
- One listener is attached to the
<ul>. - Button clicks bubble to the list.
classList.contains("remove")checks whether the clicked element is a Remove button.closest("li")finds the item’s parent list element.remove()removes that item.- This is a practical use of event delegation.
Question 10: Build a Dynamic List Using Event Delegation
Problem
Create a small task manager where users can:
- Add tasks.
- Click a task to mark it complete.
- Remove a task.
- Use only one click listener for the task list.
Solution
<input
type="text"
id="taskInput"
placeholder="Enter a task"
>
<button id="addButton">Add Task</button>
<ul id="taskList"></ul>
<script>
const taskInput = document.getElementById("taskInput");
const addButton = document.getElementById("addButton");
const taskList = document.getElementById("taskList");
addButton.addEventListener("click", function() {
const taskText = taskInput.value.trim();
if (taskText === "") {
return;
}
const item = document.createElement("li");
item.innerHTML = `
<span class="task">${taskText}</span>
<button class="remove">Remove</button>
`;
taskList.appendChild(item);
taskInput.value = "";
});
taskList.addEventListener("click", function(event) {
if (event.target.classList.contains("task")) {
event.target.classList.toggle("completed");
}
if (event.target.classList.contains("remove")) {
const item = event.target.closest("li");
item.remove();
}
});
</script>
<style>
.completed {
text-decoration: line-through;
}
</style>
Output
If the user adds:
Learn JavaScript
The list displays:
Learn JavaScript [Remove]
Clicking the task:
Learn JavaScript [Remove]
The task receives a line-through style.
Clicking Remove deletes the task.
Step-by-step Explanation
- The user enters a task.
- The Add Task button creates a new
<li>. - The task contains a
<span>and Remove button. - The new item is added to the list.
- Only one click listener is attached to the entire task list.
- When a task is clicked, event bubbling sends the event to the list.
event.targetidentifies what was clicked.- If the task was clicked,
classList.toggle()adds or removes the completed class. - If Remove was clicked,
closest("li")finds the task container. remove()deletes the task.- Even dynamically created tasks work without adding individual listeners.
Key Takeaways
- Event propagation describes how an event travels through the DOM.
- Event propagation has capturing, target, and bubbling phases.
- Event capturing travels from the outer element toward the target.
- Event bubbling travels from the target toward its ancestors.
event.targetidentifies the element where the event originally occurred.event.currentTargetidentifies the element whose event listener is currently running.event.stopPropagation()stops further propagation.- Event delegation uses a parent element to handle events from its children.
- Event delegation works because of event bubbling.
closest()can find the nearest matching ancestor.- Event delegation is particularly useful for dynamically created elements.
- Event delegation can reduce the number of event listeners in large interfaces.
FAQs
1. What is event bubbling in JavaScript?
Event bubbling is the process where an event moves from the target element upward through its parent elements.
For example:
Button
↓
Parent
↓
Container
↓
Document
A click on a button can therefore trigger click listeners attached to its ancestors.
2. What is event capturing?
Event capturing is the phase where an event travels from an outer ancestor toward the target element.
For example:
Document
↓
Container
↓
Parent
↓
Button
You can enable capturing by passing true as the third argument:
element.addEventListener("click", function() {
console.log("Clicked");
}, true);
3. What is the difference between event bubbling and capturing?
The main difference is the direction of event propagation.
Capturing:
Parent → Child
Bubbling:
Child → Parent
Most event listeners are commonly used with the bubbling phase.
4. What is event delegation?
Event delegation is a technique where one parent element handles events from multiple child elements.
For example:
list.addEventListener("click", function(event) {
if (event.target.tagName === "LI") {
console.log(event.target.textContent);
}
});
Instead of adding separate listeners to every <li>, one listener is attached to the parent list.
5. What is event.target?
event.target identifies the element where the event originally occurred.
For example, if a button is clicked inside a <div>:
parent.addEventListener("click", function(event) {
console.log(event.target);
});
The target will be the button.
6. What is event.currentTarget?
event.currentTarget refers to the element whose event listener is currently executing.
For example:
parent.addEventListener("click", function(event) {
console.log(event.currentTarget);
});
If the listener is attached to parent, currentTarget refers to parent.
7. Why is event delegation useful?
Event delegation is useful because it:
- Reduces the number of event listeners.
- Works well with dynamic elements.
- Makes list and menu handling easier.
- Can improve code organization.
- Avoids attaching separate listeners to many similar elements.
Written by Shubhranshu Shekhar, who has trained 20000+ students in coding.
