Search code examples
javascripthtmlcssdom-eventsweb-component

Listening to Events from Web Components Not Working


I'm trying to make my Web Component also communicate with the outside through events. So far, emitting events seems ok, but not receiving events, for some reason.

I've already tried many variations with bubbles and composed, and also attaching the emitter to the web component's shadowRoot, but it didn't work.

What am I missing here? (Also: why is the background color of the container below not yellow?)

class HookbanContainer extends HTMLElement {
  connectedCallback() {
    const template = document.createElement("template")
    template.innerHTML = /* html */ `
      <style>
        :host {
          background-color: yellow;
        }
      </style>

      <slot></slot>
    `

    const shadowRoot = this.attachShadow({ mode: "open" })
    shadowRoot.appendChild(template.content.cloneNode(true))

    shadowRoot.addEventListener(
      "hookban-test",
      (e) => console.log("test", e)
    )
  }
}

customElements.define("hookban-container", HookbanContainer)
<hookban-container>
  <p>hello</p>
</hookban-container>

<button>Trigger Event</button>

<script>
  const triggerEvtButton = document.querySelector("button")
  
  triggerEvtButton.onclick = () => {
    document.dispatchEvent(
      new CustomEvent("hookban-test", {
        bubbles: true,
        composed: true,
        detail: {
          content: "test"
        }
      })
    )
  }
</script>


Solution

  • Events dispatched to document aren't triggered on any child elements including open shadow roots, listen rather document in your web component :

    class HookbanContainer extends HTMLElement {
      connectedCallback() {
        const template = document.createElement("template")
        template.innerHTML = /* html */ `
          <style>
            :host {
              background-color: yellow;
            }
          </style>
    
          <slot></slot>
        `
    
        const shadowRoot = this.attachShadow({ mode: "open" })
        shadowRoot.appendChild(template.content.cloneNode(true))
    
        document.addEventListener(
          "hookban-test",
          (e) => console.log("test", e)
        )
      }
    }
    
    customElements.define("hookban-container", HookbanContainer)
    <hookban-container>
      <p>hello</p>
    </hookban-container>
    
    <button>Trigger Event</button>
    
    <script>
      const triggerEvtButton = document.querySelector("button")
      
      triggerEvtButton.onclick = () => {
        document.dispatchEvent(
          new CustomEvent("hookban-test", {
            bubbles: true,
            composed: true,
            detail: {
              content: "test"
            }
          })
        )
      }
    </script>