Hacker News new | ask | show | jobs
by irjoe 469 days ago
Using document.addEventListener means it will work even if the DOM is updated without having to add new event listeners. If I'm not expecting the DOM to change I would be more inclined to do something like:

  document.querySelectorAll('.menu-wrapper')).forEach(menuWrapper => {
    const button = menuWrapper.querySelector('.menu-opener');
    const content = menuWrapper.querySelector('.menu-content');

    if (!content || !button) {
      return;
    }

    button.addEventListener(() => {
      button.setAttribute('aria-expanded', 'true');
      menu.showPopover();
    });

    content.addEventListener('toggle', e => {
      // reset back to aria-expanded=false on close
      if (e.newState == 'closed') {
        button.setAttribute('aria-expanded', 'false');
      }
    });
  });
The React example seems a little odd as well, if the "open" callback actually called "showPopover()" instead of only calling "setIsOpen" then the "useEffect" could be entirely redundant. The resulting code would be a lot clearer imo.
1 comments

> it will work even if the DOM is updated without having to add new event listeners

Nailed it.

And the sibling comment got at it but the "magic phrase" to Google for this technique is "event delegation." Two more phrases: delegation relies on "event bubbling," bubbling can be interrupted with "event capturing." (You will rarely want to capture events, it's JS's `!important` equivalent)

One decent overview: https://javascript.info/bubbling-and-capturing