Jason
Jason

Reputation: 4159

Reference web component root attribute with CSS

Created a web component with a shadow DOM. When the button is clicked it adds the open attribute to the web component.

I would like to show the hidden div in the CSS when the open is added with CSS styling. Is it possible for the shadow DOM styles to reference attributes on the web component root? Otherwise, I have to add a superfluous class or attribute within the shadow DOM.

class CustomComponent extends HTMLElement {
  constructor() {
    super();
    
    this.element = this.attachShadow({mode: 'open'});
  }
  
  static get observedAttributes() {
    return ['open'];  
  }
  
  attributeChangedCallback(attrName, oldValue, newValue) {
    if (newValue !== oldValue) {
      this[attrName] = this.hasAttribute(attrName);
    }
  }
  
  connectedCallback() {
    const template = document.getElementById('custom-component');
    const node = document.importNode(template.content, true);
    this.element.appendChild(node);
    
    this.element.querySelector('button').addEventListener('click', () => {
      this.setAttribute('open', '');
    });
  }
}

customElements.define('custom-component', CustomComponent);
<template id="custom-component">
  <style>
    div {
      display: none;
    }
    [open] div {
      display: block;
    }
  </style>
  <button>Open</button>
  <div>Content</div>
</template>

<custom-component></custom-component>

Upvotes: 1

Views: 1055

Answers (1)

Jason
Jason

Reputation: 4159

It appears the host CSS pseudo selector is designed to handle this precise situation.

class CustomComponent extends HTMLElement {
  constructor() {
    super();
    
    this.element = this.attachShadow({mode: 'open'});
  }
  
  static get observedAttributes() {
    return ['open'];  
  }
  
  attributeChangedCallback(attrName, oldValue, newValue) {
    if (newValue !== oldValue) {
      this[attrName] = this.hasAttribute(attrName);
    }
  }
  
  connectedCallback() {
    const template = document.getElementById('custom-component');
    const node = document.importNode(template.content, true);
    this.element.appendChild(node);
    
    this.element.querySelector('button').addEventListener('click', () => {
      this.setAttribute('open', '');
    });
  }
}

customElements.define('custom-component', CustomComponent);
<template id="custom-component">
  <style>
    div {
      display: none;
    }
    :host([open]) div {
      display: block;
    }
  </style>
  <button>Open</button>
  <div>Content</div>
</template>

<custom-component></custom-component>

Upvotes: 1

Related Questions