Search code examples
javascripthtmlcsseventscss-grid

Why does event bubbling not work when using css grid with elements occupying the same cell?


I have two grid children that occupy the same cell. They both have click event listeners. According to event bubbling, both event listeners should be fired when I click on the cell.

const outer = document.getElementById('outer')
outer.addEventListener('click', () => console.log('on outer click'))

const inner1 = document.getElementById('inner1')
inner1.addEventListener('click', () => console.log('on inner1 click'))

const inner2 = document.getElementById('inner2')
inner2.addEventListener('click', () => console.log('on inner2 click'))
#outer {
  width: 100vw;
  height: 100vh;
  display: grid;
}

#inner2 {
  grid-column: 1/2;
  grid-row: 1/2;
}

#inner1 {
  grid-column: 1/2;
  grid-row: 1/2;
}
<div id="outer">
  <div id="inner1">

  </div>
  <div id="inner2">

  </div>
</div>

Playground: https://jsfiddle.net/o10sfpwu/

Expected log:

on inner2 click
on inner1 click
on outer click

Actual log:

on inner2 click
on outer click

Why is the inner1 event listener not fired? The click event should bubble through all elements occupying this space, right?


Solution

  • The click event should bubble through all elements occupying this space, right?

    The click event (or any event) will only bubble through the DOM ancestors of an element. The position of the element is not considered, nor is whether the position overlaps with another element while an event is bubbling.

    In this case, because the inner2 is at the same cell as inner1, and inner2 is put after inner1 in the DOM, the inner2 will be on top of the inner1. So, clicking on that cell results in an event being dispatched to the inner2. Then, to see which other elements see the event while bubbling, look at inner2's ancestors:

    <div id="outer">
      <div id="inner1">
    
      </div>
      <div id="inner2">
    
      </div>
    </div>
    

    But its ancestors are only #outer (and the document.body, and the document.documentElement). inner1 is not an ancestor, and the event was dispatched to inner2, so the event does not bubble through inner1.

    This is described in your MDN link:

    In the bubbling phase:

    • The browser checks to see if the element that was actually clicked on has an onclick event handler registered on it in the bubbling phase, and runs it if so.

    • Then it moves on to the next immediate ancestor element and does the same thing, then the next one, and so on until it reaches the element.