Recipe 12.6

Creating a Disclosure Component

This example builds a disclosure element, which has a toggle button and some child content. The toggle button will show and hide the child content.

Demo

Details
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras feugiat quis ipsum in ultrices. Maecenas dignissim urna a odio sagittis consectetur. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Nunc sed porttitor lacus. Pellentesque eu facilisis libero. Mauris malesuada gravida sem, sit amet ornare elit rutrum ut. Proin ut urna sit amet arcu pellentesque scelerisque a vitae augue. Sed viverra tellus nec libero molestie, quis ultricies sapien vestibulum. Cras nibh nibh, consequat non eros ullamcorper, gravida tincidunt nunc.

Code

JavaScript
const template = document.createElement('template');
template.innerHTML = `
  <div>
    <button type="button" class="toggle-button">
      <slot name="title"></slot>
    </button>
    <div class="content">
      <slot></slot>
    </div>
  </div>
`;

class Disclosure extends HTMLElement {
  static observedAttributes = ['open'];

  constructor() {
    super();
    this.attachShadow({ mode: 'open' });
    this.shadowRoot.appendChild(template.content.cloneNode(true));

    this.content = this.shadowRoot.querySelector('.content');
  }

  connectedCallback() {
    this.content.hidden = !this.hasAttribute('open');
    this.shadowRoot.querySelector('.toggle-button')
      .addEventListener('click', () => {
        if (this.hasAttribute('open')) {
          this.removeAttribute('open');
          this.content.hidden = true;
        } else {
          this.setAttribute('open', '');
          this.content.hidden = false;
        }
      });
  }

  attributeChangedCallback(name, oldValue, newValue) {
    if (newValue !== null) {
      this.content.hidden = false;
    } else {
      this.content.hidden = true;
    }
  }
}

if (!customElements.get('x-disclosure')) {
  customElements.define('x-disclosure', Disclosure);
}
HTML
<style>
  x-disclosure:not(:defined) {
    display: none;
  }
</style>

<x-disclosure>
  <div slot="title">Details</div>
  Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras feugiat quis ipsum in ultrices. Maecenas dignissim urna
  a odio sagittis consectetur. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos
  himenaeos. Nunc sed porttitor lacus. Pellentesque eu facilisis libero. Mauris malesuada gravida sem, sit amet ornare
  elit rutrum ut. Proin ut urna sit amet arcu pellentesque scelerisque a vitae augue. Sed viverra tellus nec libero
  molestie, quis ultricies sapien vestibulum. Cras nibh nibh, consequat non eros ullamcorper, gravida tincidunt nunc.
</x-disclosure>
Web API Cookbook
Joe Attardi