'Why does my shadow dom break my custom element?

Here is a JSFiddle demonstration of the custom element: https://jsfiddle.net/c4bLo097/5/

Here is the code from the fiddle:

JavaScript:

window.customElements.define('test-element', class TestElement extends HTMLElement {
    constructor() {
    super()

    let contents = `
      <style>
        :host {
          display: block;
        }
        :host([hidden]) {
          display: none;
        }
      </style>`

    // convert string to nodes
    let template = document.createElement('template')
    template.innerHTML = contents

    // create shadow
    this.attachShadow({mode: 'open'})

    // insert nodes
    this.shadowRoot.appendChild(template.content.cloneNode(true))
  }
})

HTML:

<test-element>
    This element should have a natural height.

    <div style="height: 300px;"></div>

    I should be able to see this text on a green background.
</test-element>

CSS:

test-element {
  width: 200px;
  background: green;
}

If you inspect <custom-element> with your developer tools, you should see that the shadow is there. But my element will not render its height correctly.

Here is an example JSFiddle of what I'm trying to achieve: https://jsfiddle.net/9483s1qb/2/



Solution 1:[1]

When you add shadowDOM the content of your element becomes "lightDOM"..

It is no longer displayed in the main DOM and not part of your shadowDOM.

As Supersharp explained in 2017:

The Light DOM is simply the plain old DOM tree inside a HTML element.

The term is only used in context of Web Components (Custom Elements WITH Shadow DOM)
I suppose the normal DOM was redefined as Light in contrast with Shadow.

The WHATWG specs call it the shadowroot host's node tree, or light tree:

The Shadow DOM is the added DOM that recovers, masks, or replaces the normal DOM,
as explained in the article from Google.

You have to transfer lightDOM content to shadowDOM yourself:

customElements.define('my-element', class extends HTMLElement {
    constructor() {
    //create shadowDOM (thus creating lightDOM) and append Template
    super() /* return this */
        .attachShadow({mode: 'open'}) /* SETs and RETURNs this.shadowRoot */
        .append(document.getElementById(this.nodeName).content.cloneNode(true))
  }
  connectedCallback(){
    //append content from lightDOM
    this.shadowRoot.append(...this.querySelectorAll('DIV'));
  }
})
my-element{
  border: 1px dashed blue;
}
<template id="MY-ELEMENT">
  <style>
    :host {
      display: block;
      font-size:20px;
    }
    h4{
      background:yellow;
      margin: .5em 0;
    }
    div{
      background:lightcoral;
    }
  </style>
  <h4><slot name="title"></slot></h4>
</template>

<my-element>
  <!-- begin lightDOM because my-element has shadowDOM -->
  <span slot="title">whole SPAN is slotted</span>
  <div>I am appended</div>
  <div>appended too</div>
  <p>I remain (invisible) in lightDOM</p>
  <!-- end lightDOM -->
</my-element>

<my-element>
  <!-- begin lightDOM because my-element has shadowDOM -->
  <span slot="title">slotted too</span>
  <div>appended again</div>
  I remain (invisible) in lightDOM
  <!-- end lightDOM -->
</my-element>

Snippet Notes:

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1