Search code examples
javascripthtmlshadow-dom

How do I prevent a Slotted HTML element from rendering until is it inside the shadowRoot?


I have a very simple site similar to this jsfiddle. Everything seems to work fine but on my local one, but when I stop at the first JS line (before the custom elements are declared) I can see the div with no formatting...

<jrg-test>
  <div slot="test">
      This should work
  </div>
</jrg-test>

connectedCallback() {
  console.log("Ok we are working")
  this.shadowRoot.innerHTML = "<slot name='test'></slot>"
  const element = document.createElement('style');
  element.textContent = "::slotted(*){background-color:red;color:white;}";
  this.shadowRoot.appendChild(element);
}

So basically if I stop before the custom element is rendered I see the raw div. I know there are some hacky solutions involving positioning and CSS but is there a cleaner solution. Possibly one I can implement exclusively in JS?

So the main question is how can I hide the This should work text until the red background and white color have been applied?


Solution

  • Maybe you could try to use the :defined CSS pseudo-class to hide the custom element while it's defined.

    See the example below:

    class TestElement extends HTMLElement{
      constructor(){
        super();
        console.log("Attaching the shadow")
        this.attachShadow({mode:'open'})
      }
      connectedCallback() {
        console.log("Ok we are working")
        this.shadowRoot.innerHTML = `<style>
          ::slotted(*){background-color:red;color:white;}
          </style>
          <slot name='test'></slot>`
      }
    }
    upgrade.onclick = () => customElements.define("jrg-test", TestElement)
    jrg-test:not(:defined) {
      display:none
    }
    <jrg-test>
      <div slot="test">This should work</div>
    </jrg-test>
    
    <button id="upgrade">upgrade</button>