Script Valley
JavaScript in the Browser: DOM, Events & APIs
Events and Event HandlingLesson 2.3

Event delegation: handling clicks on dynamic elements

event delegation pattern, e.target, matches method, dynamic children, performance benefits

Event Delegation

Event delegation attaches a single listener to a parent element instead of one listener per child. Because events bubble, the parent catches all child events.

This is critical for dynamically added elements — listeners attached before an element existed do not work on that element.

const list = document.querySelector('#task-list');

list.addEventListener('click', (e) => {
  // e.target is the exact element clicked
  if (e.target.matches('.delete-btn')) {
    e.target.closest('li').remove();
  }
  if (e.target.matches('.complete-btn')) {
    e.target.closest('li').classList.toggle('done');
  }
});

Why Not One Listener Per Child?

Attaching 500 listeners for a 500-item list wastes memory and slows down the page. One delegated listener scales to any number of children at no extra cost.

The matches() Method

element.matches(selector) returns true if the element matches the CSS selector. It is the idiomatic way to filter which child triggered the parent listener.

if (e.target.matches('button[data-action="delete"]')) {
  handleDelete(e.target.dataset.id);
}

Up next

Preventing default browser behaviour on form submit and links

Sign in to track progress