JS Bits with Bill
JS Bits with Bill

JS Bits with Bill

Event Delegation with Vanilla JS

Event Delegation with Vanilla JS

JS Bits with Bill's photo
JS Bits with Bill

Published on Dec 2, 2020

2 min read

One of the most powerful and convenient techniques in jQuery is event delegation - a way in which you can add one event handler to a parent element instead of attaching multiple handlers to many child elements.

So here's how to do it in vanilla!

<ul>
  <li>Sphynx</li>
  <li>Maine Coon</li>
  <li>Bristish Shorthair</li>
</ul>
const ul = document.querySelector('ul');
ul.addEventListener('click', e => {
  const { target } = e;
  if (target.matches('li')) {
    callback(); // If target is an li, run callback
  }
});

Here we attach just one event listener to the parent ul element, but inside our handler we check if the event's target matches an li. If so, we run our callback function.

This is all well and good for simple HTML lists, but what if the list items contain children of their own?

<ul>
  <li>
    <span>Blue</span> Sphynx
  </li>
  <li>
    Maine Coon
    <span>Rarer breed</span>
  </li>
  <li>
    <span>Fiesty</span> Bristish Shorthair
  </li>
</ul>

With this more complex HTML tree, the event's target may not be the <li> element. Any one of the <li>'s child spans may be clicked and would register as the target. To handle this, we could either add some extra logic to check for the next closest element up the tree OR we can simply add a CSS pointer-events: none; rule that will force the spans to never be the target of pointer events:

span {
  pointer-events: none;
}

With that rule in place, even if the actual clicked element is a <span> within the <li>, the span is now considered a part of the <li>'s content and the event's target is considered to be the <li>, thus registering our callback with no fuss, no muss! 😃


Check out more #JSBits at my blog, jsbits-yo.com. Or follow me on Twitter.

 
Share this