Today I Learned

JavaScript event processing and bubbling

JavaScript event listeners and handlers can have some unnatural behaviour if we are not aware of how things work behind the hood. Let's understand what these unexpected behaviours could be and why things actually happen as they happen.

Let's pretend that we have the following DOM structure with 3 divs: grandparent, parent and child.

<div class="grandparent"></div>
  <div class="parent">
    <div class="child"></div>

All 3 divs have their custom event handlers, like follows:

grandparent.addEventListener('click', () =>  console.log('Grandparent'));
parent.addEventListener('click', () =>  console.log('Parent'));
child.addEventListener('click', () =>  console.log('Child'));

If we click on the inner div (the child div), we would expect to call the child div's event handler, but actually we will see in the console that all 3 event handlers have been called, in the following order:


Let's understand why this happens. Mainly, there are 3 phases in processing JavaScript events:

  1. Capturing phase
  • the DOM tree is parsed downwards until the caller element is found. Throughout its way, if there are nodes that explicitly require event execution in the capturing phase, their event handlers will be executed right away.
  1. Targeting phase
  • the caller element that triggered the event is being targeted
  1. Bubbling phase
  • the DOM tree is now parsed upwards until finding the document element, starting from the targeted/caller element. If on the way up we find elements with event handlers, they will be automatically called.

If we want to stop this behaviour of calling parent elements event handlers, we can use event.stopPropagation() on our last event handler that we want to be executed.