Search code examples
javascriptweb-componentshadow-domcustom-elementhtml5-template

Fallback content on an "unnamed" slot is never displayed


I'm trying to figure out how web components are working and can't fully understand rules around fallback content in slots:

I have a web-component like:

const template = document.createElement('template');
template.innerHTML = `
  <slot name="content">
    <span>fallback</span>
  </slot>
  <slot>
    <span>fallback on an anonymus slot</span>
  </slot>
  <section>...and more content form shadow DOM</section>
`;

class SomeComponent extends HTMLElement{
  constructor() {
    super();

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

window.customElements.define('some-component', SomeComponent);

and if I put this component on a page like

<some-component>
  <span slot="content">named slot content</span>
</some-component>

I never see a "fallback" content for unnamed slot:

enter image description here

but it does present in the shadow DOM:

enter image description here

I don't use any pollyfills and rely on current Chrome web-components support


Solution

  • It's the expected behavior. Actually the fallback sould not be display because some elements are caught and revealed by the unnamed <slot> element: the (invisible space and CRLF) text elements before the <span> and after the </span> tags.

    If you remove them:

    <some-component><span slot="content">named slot content</span></some-component>
    

    ...then you will see the fallback text!

    const template = document.createElement('template');
    template.innerHTML = `
      <slot name="content">
        <span>fallback</span>
      </slot>
      <slot>
        <span>fallback on an anonymus slot</span>
      </slot>
      <section>...and more content form shadow DOM</section>
    `;
    
    class SomeComponent extends HTMLElement{
      constructor() {
        super();
    
        const shadowRoot = this.attachShadow({mode: 'open'});
        shadowRoot.appendChild(template.content.cloneNode(true));
      }
    }
    
    window.customElements.define('some-component', SomeComponent);
    <some-component><span slot="content">named slot content</span></some-component>