Event Delegation Isn't Old-Fashioned. It's Just Underrated
One listener on a parent can replace hundreds on children, and the browser has made it nicer than ever.
A junior teammate once asked me why I attach click handlers to a list instead of to each list item. The honest answer was 'because I learned this in 2013'. The better answer, which took me a while to articulate, is that it is still one of the cleanest patterns the DOM offers.
The pattern in one breath
Events bubble. A click on a button inside a row travels up through the row, the table, the body and the document. So instead of putting a listener on every button, you put one on a stable ancestor and ask where the click came from.
list.addEventListener('click', (event) => {
const button = event.target.closest('[data-action]');
if (!button || !list.contains(button)) return;
handlers[button.dataset.action](button);
});
That closest call is the modern piece. It walks up from whatever was clicked, maybe an icon inside the button, and finds the element you actually care about.
Why it still earns its place
I rebuilt an inventory table last quarter that renders up to 2,000 rows. The previous version attached four listeners per row. Here is what changed when I switched to delegation:
- Memory went down. Eight thousand closures became one.
- Rendering got simpler. New rows needed no setup code, so infinite scroll stopped having a 'did we bind the handlers?' bug.
- Teardown disappeared. Removing a row no longer meant remembering to remove its listeners.
The third point is the one I underestimated. A whole category of leaks simply cannot happen when there is nothing to forget.
When frameworks do it for you
If you write React, you are already using delegation; the library attaches listeners at the root and dispatches internally. That is a good reason to understand the pattern, not a reason to ignore it. The moment you drop into a web component, a vanilla widget, or a third-party embed, you are back to managing listeners yourself.
The sharp edges
- Some events, like
focusandblur, do not bubble. Usefocusinandfocusoutinstead. mouseenterdoes not bubble either;mouseoverdoes, but fires more often than you expect.- Keep the handler cheap. One listener running on every click in a large region should exit early when the target is irrelevant.
Old techniques are not automatically outdated. Some are just finished: small, correct, and waiting for us to remember them.
Cover: Photo by Juanjo Jaramillo on Unsplash.