Open Shadow DOM

Recipe 12.3 Focus elements in Shadow DOM

Sample:

Here's more content…

Code:

<the-button></the-button>
<script>
  class TheButton extends HTMLElement {
  constructor() {
    super();
    this.attachShadow({
      mode: "open" <!--(1)-->
    });

    const button = document.createElement("button");
    button.textContent = "Hello World";
    this.shadowRoot.append(button);
  }
}

customElements.define("the-button", TheButton);

const theButton = document.querySelector('the-button');
console.log(theButton.shadowRoot.querySelectorAll('button').length)
// returns 1
</script>

<the-disclosure>
  <p>Here's more content…</p>
</the-disclosure>

<template id="disclosure">
  <button aria-expanded="false">Details</button>
  <div class="content" hidden>
    <slot></slot>
  </div>
</template>

<script>
class TheDisclosure extends HTMLElement {
  constructor() {
    super();

    this.attachShadow({ mode: "open" });

    let template = document.getElementById("disclosure"); 
    let templateContent = template.content;
    this.shadowRoot.appendChild(templateContent.cloneNode(true));

    this._attachStyles();

    const button = this.shadowRoot.querySelector("button");
    this._expanded = button.getAttribute("aria-expanded"); 
    button.addEventListener("click", this._toggle);
  }

  _attachStyles() {
    const style = document.createElement("style");
    style.textContent = `
      [aria-expanded="true"] + .content {
        display: block;
      }
    `;

    this.shadowRoot.appendChild(style);
  }

  _toggle() {
    this._expanded = !this._expanded;
    this.setAttribute("aria-expanded", this._expanded);
  }
}

customElements.define("the-disclosure", TheDisclosure);
</script>