Jens Törnell
Jens Törnell

Reputation: 24798

Slots does not work on a html web component without shadow dom

I have a html web component without shadow dom and I try to add a slot. For some reason it does not work.

I expected it to switch "Foo bar" to "Hello world" but that does not happen.

  1. Does slots only works with shadow dom and a template?
  2. How can I get it to work?

class HelloWorld extends HTMLElement {
  constructor() {
    super();
  }

  connectedCallback() {
    this.innerHTML = `
      <div>
        <slot name="element-name">Foo Bar</slot>
      </div>
    `;
  }
}

customElements.define("hello-world", HelloWorld);
<hello-world>
  <span slot="element-name">Hello World</span>
</hello-world>

Upvotes: 11

Views: 4661

Answers (1)

Yes, <slot> only works inside shadowDOM in a native (JSWC) Web Component

or native HTML Element (you can attach shadowDOM to)

Slotted content is reflected lightDOM content

See: ::slotted CSS selector for nested children in shadowDOM slot

A Web Component without shadowDOM only has innerHTML

If you do this.innerHTML= on such a Web Component it replaces the innerHTML, just like on any other HTML tag

with shadowDOM:

<hello-world>
  <b slot="none">Mighty</b>
  <span slot="title">Web Components</span>
  Hello! 
</hello-world>

<script>
customElements.define("hello-world", class extends HTMLElement {
  constructor() {
    super()
      .attachShadow({mode:"open"})
      .innerHTML = `<slot>default</slot>` + // default - slotting anything NOT slotted
                   `<slot name="title">Foo Bar</slot>`;
    this.onclick = (evt) => this.querySelector('b').slot = "title";
  }
});
</script>

Do not fall into this one!

You are dealing with HTML!

  • Whitespace and linebreaks in HTML are slotted to the default slot!

  • not existing slotnames are ignored,
    content does not go to the default <slot>!!
    The slotname can be changed with JS, see above.

  • <!-- comments --> are ignored

  • The default content of any <slot> is not slotted content!

<hello-world><span slot="title">Web Components rule!</span></hello-world>

<hr>

<hello-world><!-- comment --><span slot="notAslotname">Frameworks are cool!</span></hello-world>

<hr>

<hello-world>
  <span slot="title">Web Components are cool!</span>
</hello-world>


<script>
customElements.define("hello-world", class extends HTMLElement {
  constructor() {
    super()
      .attachShadow({mode:"open"})
      .innerHTML = `&lt;${this.localName}> ` +
        `<style>::slotted(*){background:lightgreen}</style>` + 
        `<slot>No whitespace or linebreaks! </slot> ` + // default - slotting anything NOT slotted
        `<slot name="title">Web Components take <b>some</b> time to learn</slot>`;
  }
});
</script>

Upvotes: 12

Related Questions