Lesson 8: Event Delegation

Learning Objectives

By the end of this lesson, learners will be able to:

  • Understand what event delegation is
  • Know why adding individual event listeners to many elements is inefficient
  • Grasp the concept of event bubbling
  • Use event.target and event.currentTarget correctly
  • Apply delegation to handle events on dynamically created elements

Why Care About Event Delegation?

Let’s say you have a list of 100 items, and each should respond to a click.

If you do:

listItem1.addEventListener("click", ...);
listItem2.addEventListener("click", ...);
...
listItem100.addEventListener("click", ...);

✅ This works, but it is:

  • Wasteful (100 event listeners in memory)
  • Hard to manage (what if you have 1000 items?)
  • Doesn’t work for dynamically added items unless you re-add listeners

Event delegation solves these problems by using a single event listener on a common parent.


What Is Event Delegation?

Event delegation means:

  • Attach one event listener to a parent element
  • When any child is clicked, the event “bubbles” up to the parent
  • The parent decides what to do based on which child was clicked

✅ This is faster, cleaner, and easier to maintain — especially with dynamic elements.


What is Event Bubbling?

In the DOM, when an event happens (like a click), it first runs on the target element and then bubbles up through its ancestors (parent, grandparent, all the way to document).

That’s why if you put an event listener on the parent, it can “catch” events from its children.


target vs currentTarget

PropertyMeaning
event.targetThe exact element that was clicked
event.currentTargetThe element the event handler was attached to (the parent)

✅ In event delegation, you almost always use event.target to check which child was clicked.


Example: Dynamically Added List Items

Let’s say you build a to-do list where the user can add new tasks:

HTML:

<ul id="task-list">
  <li>First Task</li>
</ul>
<button id="add-task">Add Task</button>

JavaScript:

let list = document.getElementById("task-list");
let addBtn = document.getElementById("add-task");

addBtn.addEventListener("click", function() {
  let li = document.createElement("li");
  li.textContent = "New Task";
  list.appendChild(li);
});

✅ If you put a click listener on each <li> you’d have to re-add the listener every time you create a new one.

Instead, use delegation on the parent:

list.addEventListener("click", function(event) {
  if (event.target.tagName === "LI") {
    event.target.classList.toggle("completed");
  }
});

🧠 This means:

  • One event listener on the <ul>
  • Works for existing items and new items added dynamically
  • Toggling the completed class updates the style

Example CSS

.completed {
  text-decoration: line-through;
  color: gray;
}

Clicking any <li> will now mark it as completed — even if it was added later.


Best Practices

  • Attach the delegated listener as high in the DOM as reasonable (not the entire document unless needed)
  • Always check event.target inside the handler to see which element triggered the event
  • Combine delegation with class checking if there are many different children:
if (event.target.classList.contains("delete-btn")) {
  // do delete logic
}

Practice Challenge

HTML:

<ul id="color-list">
  <li>Red</li>
  <li>Blue</li>
  <li>Green</li>
</ul>
<button id="add-color">Add Color</button>

Task:

  • Add a new <li> with text "Yellow" each time the button is clicked
  • When any <li> is clicked, toggle a highlight class

✅ Example JavaScript:

let list = document.getElementById("color-list");
let button = document.getElementById("add-color");

button.addEventListener("click", function() {
  let li = document.createElement("li");
  li.textContent = "Yellow";
  list.appendChild(li);
});

list.addEventListener("click", function(event) {
  if (event.target.tagName === "LI") {
    event.target.classList.toggle("highlight");
  }
});

Summary

ConceptDescription
Event delegationOne listener on parent handles many children
Event bubblingEvents travel upward through the DOM tree
targetElement that was actually clicked
currentTargetElement the handler is attached to