Search code examples
javascriptcssweb-componentcustom-component

Why styles don't apply to all slot elements in a custom web component?


I have a custom unordered list web component built out. I'm trying to set a custom bullet on each <li>, but the bullet is only applying to the first list item.

How can I apply the same style to all list items?

const template = document.createElement('template');
template.innerHTML = `
  <style>
    ul {
      list-style-type: none;
      padding: 2.5rem 0;
      margin-block-start: 0;
      margin-block-end: 0;
    }
    ul li {
      background-image: url("https://www.nextiva.com/assets/svg/bullet.svg");
      background-position: 0 0.725rem;
      background-repeat: no-repeat;
      padding-left: 1.125rem;
      margin: 2rem 0;
      font-size: 1.25rem;
      line-height: 2rem;
    }
    ul li:first-child, ul li:last-child {
      margin: 0;
    }
  </style>
  <ul>
    <li><slot name="item"></slot></li>
  </ul>
`;

class CustomBulletList extends HTMLElement {

  constructor() {
    super();

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

window.customElements.define('custom-bullet-list', CustomBulletList);
<custom-bullet-list>
  <li slot="item">Lollipop</li>
  <li slot="item">Fruit Toast</li>
  <li slot="item">Cup Cake</li>
</custom-bullet-list>


Solution

  • Change ul li to ::slotted(li).

    MDN got example of use-case close to what you trying to do.

    Snippet:

    const template = document.createElement('template');
    template.innerHTML = `
      <style>
        ul {
          list-style-type: none;
          padding: 2.5rem 0;
          margin-block-start: 0;
          margin-block-end: 0;
        }
        
        ::slotted(li) {
          background-image: url("https://www.nextiva.com/assets/svg/bullet.svg");
          background-position: 0 0.725rem;
          background-repeat: no-repeat;
          padding-left: 1.125rem;
          margin: 2rem 0;
          font-size: 1.25rem;
          line-height: 2rem;
        }
        ul li:first-child, ul li:last-child {
          margin: 0;
        }
      </style>
      <ul>
        <li><slot name="item"></slot></li>
      </ul>
    `;
    
    class CustomBulletList extends HTMLElement {
    
      constructor() {
        super();
    
        this.showInfo = true;
        this.attachShadow({
          mode: 'open'
        });
        this.shadowRoot.appendChild(template.content.cloneNode(true));
      }
    }
    
    window.customElements.define('custom-bullet-list', CustomBulletList);
    <custom-bullet-list>
      <li slot="item">Lollipop</li>
      <li slot="item">Fruit Toast</li>
      <li slot="item">Cup Cake</li>
    </custom-bullet-list>