Search code examples
htmlweb-componentshadow-dom

`document` doesn't refer to the shadowDom


So I have code that's something like this:

<template id="cool-btn-template">
  <script>
    const button = document.getElementById('click-me');
    button.addEventListener('click', event => alert(event));
  </script>
  <style>
    #click-me {
      all: unset;
      background: tomato;
      border: 0;
      border-radius: 4px;
      color: white;
      font-family: Helvetica;
      font-size: 1.5rem;
      padding: .5rem 1rem;
    }
  </style>
  <button id="click-me">Log click event</button>
</template>

<cool-btn></cool-btn>

<script>
  class CoolBtn extends HTMLElement {
    constructor() {
      super();
      const template = document.getElementById('cool-btn-template');
      const shadowRoot = this.attachShadow({mode: 'open'});
      shadowRoot.appendChild(template.content.cloneNode(true));
    }
  }

  customElements.define('cool-btn', CoolBtn);
</script>

If you run the code, you'll notice that document in the template's script tag refers to the overall document, not the shadowDom. How do I make document mean its shadowDom?


Solution

  • I believe all JavaScript for a custom element is meant to go inside its class, which is how you scope it to the element:

    <template id="cool-btn-template">
      <style>
        #click-me {
          all: unset;
          background: tomato;
          border: 0;
          border-radius: 4px;
          color: white;
          font-family: Helvetica;
          font-size: 1.5rem;
          padding: .5rem 1rem;
        }
      </style>
      <button id="click-me">Log click event</button>
    </template>
    
    <cool-btn></cool-btn>
    
    <script>
      class CoolBtn extends HTMLElement {
        constructor() {
          super();
          const template = document.getElementById('cool-btn-template');
          const shadowRoot = this.attachShadow({mode: 'open'});
          shadowRoot.appendChild(template.content.cloneNode(true));
          shadowRoot.getElementById('click-me').addEventListener('click', event => alert(event))
        }
      }
    
      customElements.define('cool-btn', CoolBtn);
    </script>