[SO] Custom Events, bubbles, composed

by Danny Engelman

HTML

<my-component id=ONE></my-component>
<my-component id=TWO composed>
  <my-component id=INSIDETWO composed></my-component>
</my-component>
<my-component id=THREE composed bubbles>
  <my-component id=INSIDETHREE composed bubbles></my-component>
</my-component>

<script>
  let log = (evt, label, ...args) => {
    let div = document.createElement("div");
    div.classList.add(evt.target.id, evt.type);
    div.innerHTML = `${label} received ${evt.type} from ${evt.target.id}`;
    console.log(evt.type, evt.target);
    document.body.append(div);
  }
  document.addEventListener("click", (evt) => log(evt, 'document'));
  document.addEventListener("MyEvent", (evt) => log(evt, 'document'));
  customElements.define('my-component', class extends HTMLElement {
    constructor() {
      const attr = (x) => this.getAttribute(x),
        has = (x) => this.hasAttribute(x) ? x : "",
        label = () => `${attr('id')} : ${has('COMPOSED')} ${has('BUBBLES')} `,
        html = () => `<button id="${attr('id')}">${label()}</button><br><slot></slot>`;
      super().attachShadow({
        mode: 'open'
      }).innerHTML = html();
      let button = this.shadowRoot.querySelector("button");
      button.addEventListener("click", (evt) => {
        log(evt, `button inside ${this.id}`);
        button.dispatchEvent(new CustomEvent("MyEvent", {
          bubbles: this.hasAttribute("bubbles"),
          composed: this.hasAttribute("composed")
        }));
      });
      this.addEventListener("MyEvent", (evt) => log(evt, this.id)) // same location as DOMlistener below
    }
  });
  [...document.querySelectorAll("my-component")].forEach(el => {
    el.addEventListener("MyEvent", (evt) => log(evt, "DOMlistener_" + el.id));
  })

</script>

CSS

body{
    font:14px arial;
}
div{
  padding:.1em .2em;
}
my-component{
  padding:.5em;
  display:inline-block;
  height:1em;
}
#ONE,.ONE{
  background:lightcoral;
}
#TWO,.TWO{
  background:pink
}
#INSIDETWO,.INSIDETWO{
  background:orange;
}
#THREE,.THREE{
  background:lightgreen
}
#INSIDETHREE,.INSIDETHREE{
  background:gold;
}
.MyEvent{
  font-weight:bold;
}