stenciljsslotslots

How to reference a Stenciljs <slot /> from the HTML page?


In case I have multiple <slot />s nested inside my Stencil component, I would need to give them names, and then reference them inside my HTML page when using that component. So, how do I do that?

Example:

  render() {
    return(
      <div>
        <button><slot name="one" /></button>
        <select>
          <option value="one"><slot name="two" /></option>
        </select>
        <p> <slot name="three" /></p>
      </div>
    )
  }

And then when I am adding this component, how do I add content to each <slot />?

I have tried what is explained here: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/slot but it's not working! I have tried the following in my HTML page:

<span slot="two">dfdf</span> 
<slot name="two"><span>gdgdg</span></slot> 

Neither work!


Solution

  • The example in the MDN documentation is about as clear as you can get.
    I only deleted content from the example <template> to focus on just the <slot> elements:

    customElements.define("slot-example", class extends HTMLElement{
      constructor(){
        super()
         .attachShadow({mode:"open"})
         .append(document.getElementById(this.nodeName).content.cloneNode(true));
      }
    });
    <template id="SLOT-EXAMPLE">
      <style>span { color:red }</style>
      <slot name="element-name">NEED NAME</slot>
      <span><slot name="description">NEED DESCRIPTION</slot></span>
      <slot name="attributes"><p>None</p></slot>
    </template>
    
    <slot-example>
      <span slot="element-name">slot-example</span>
      <span slot="description">This demonstrates slot</span>
    </slot-example>
    
    <slot-example>
      <b slot="element-name">another slot-example</b>
      <b slot="attributes">Explain to yourself why this is bold and not a paragraph</slot>
    </slot-example>

    For a deep, deep, very deep dive into styling slots with ::slotted see: ::slotted CSS selector for nested children in shadowDOM slot

    Addition after comments

    Here some inspiration to get you started:

    customElements.define("my-select", class extends HTMLElement{
      connectedCallback(){
        setTimeout(()=>{ // ! wait till innerHTML is parsed
          this.innerHTML = 
              "<SELECT>" + 
              this.innerHTML
                  .split("\n")
                  .filter(Boolean)
                  .map(company=>`<OPTION>${company.trim()}</OPTION>`);
              "</SELECT>";
        });
      }
    });
    <my-select>
    Apple
    Microsoft
    Google
    Mozilla
    </my-select>