javascriptweb-componentshadow-domnative-web-component

Manual slotAssignment doesn't assign contents


class RealTodo extends HTMLElement {
    constructor() {
        super();
        this.attachShadow({ mode: "open", slotAssignment: "manual" });
    }

    connectedCallback() {
        const todoTemplate = document.getElementById("todo_template");
        const todoApp = todoTemplate.content.cloneNode(true);
        this.shadowRoot.appendChild(todoApp);

        const slot = this.shadowRoot.querySelector("slot");
        console.log(slot);

        const li = document.createElement("li");
        li.textContent = "Buy food";
        slot.assign(li);
    }
}
customElements.define("real-todo", RealTodo);
    <template id="todo_template">
    <h1>TODO LIST</h1>
        <ol>
            <slot></slot>
        </ol>
    </template>
  
  <real-todo></real-todo>

I try to assign content inside shadowDom's slot manually. It doesn't assign. No error show. I tested in firefox, chrome.

According to spec slot.assign(nodes); will assign inside slotAssignment: "manual" shadowdom


Solution

  • Your const li = document.createElement("li"); creates a Node in memory

    SLOTElement.assign() only accepts existing DOM Element(s) in first level lightDOM

    And you don't want to use append[Child](), because that moves a DOM Element

    customElements.define("real-todo", class extends HTMLElement {
      constructor() {
        const button = (props) => Object.assign(document.createElement("button"),props);
        super()
          .attachShadow({mode: "open", slotAssignment: "manual" })
          .append(
            button({ innerHTML:"Food"   , onclick : e => this.showlist("food")   }),
            button({ innerHTML:"Animals", onclick : e => this.showlist("animal") }),
            document.getElementById(this.nodeName).content.cloneNode(true)
          );
      }
      connectedCallback(){
        this.showlist();
      }
      showlist( list=this.getAttribute("list") ){
        this.shadowRoot.querySelector("span").innerHTML = list;
        const li = this.querySelectorAll(`li[list*="${list}"]`);
        this.shadowRoot.querySelector("slot").assign(...li);
      }
    });
    <template id="REAL-TODO">
        <h1>A <span></span> list</h1>
        <ol>
            <slot></slot>
        </ol>
    </template>
    
    <real-todo list="animal">
      <li list="animal">Cat</li>
      <li list="animal">Dog</li>
      <li list="food">Pie</li>
      <li list="food">Beer</li>
      <li list="food">Pizza</li>
      <li list="animal,food">Chicken</li>
      <div>
        <li list="animal,food">Never listed!!</li>
      </div>
    </real-todo>

    The inspector will show which LI elements are slotted: