Event delegation

2 snippets across 2 stacks — JavaScript, React

JSJavaScript

Event Delegation

JS · DOM Manipulation
syntax
parent.addEventListener(event, (e) => {
  if (e.target.matches(selector)) { ... }
});
example
const todoList = document.querySelector("#todo-list");

todoList.addEventListener("click", (event) => {
  const deleteBtn = event.target.closest(".delete-btn");
  if (deleteBtn) {
    const item = deleteBtn.closest(".todo-item");
    item.remove();
  }
});

Note Attach one listener to a parent instead of many on children. Works for dynamically added elements too. Use closest() to find the nearest matching ancestor.

REReact

Capture Phase & Delegation

RE · Event Handling
syntax
// Capture phase (fires before children)
<div onClickCapture={handler}>...</div>

// Event delegation: one handler on parent
<ul onClick={handleItemClick}>
  <li data-id="1">A</li>
  <li data-id="2">B</li>
</ul>
example
function ItemGrid({ items, onItemAction }) {
  function handleClick(e) {
    const itemEl = e.target.closest('[data-item-id]');
    if (!itemEl) return;

    const id = itemEl.dataset.itemId;
    const action = e.target.dataset.action;

    if (action === 'delete') {
      onItemAction(id, 'delete');
    } else if (action === 'edit') {
      onItemAction(id, 'edit');
    }
  }

  return (
    <div onClick={handleClick}>
      {items.map(item => (
        <div key={item.id} data-item-id={item.id}>
          <span>{item.name}</span>
          <button data-action="edit">Edit</button>
          <button data-action="delete">Delete</button>
        </div>
      ))}
    </div>
  );
}

Note Event delegation (one handler on a parent) reduces the number of event listeners and works well for dynamic lists. Use data-* attributes or closest() to identify which child triggered the event. React internally uses delegation at the root already.