Search code examples
javascripthtmlweb-componentshadow-domcustom-element

When I add Shadow DOM to a custom element... where does the already declared non-shadow content (Light DOM) disappear to?


TLDR: As soon as I define() a Custom Element with Shadow DOM, the Light DOM declared within the same element disappears from the browser viewport.

Why is the Light DOM within the Custom Element no longer displaying?


I am learning / experimenting with Custom Elements and Shadow DOM.

I notice that if I have the following Custom Element without any Shadow DOM, it works:

<my-company>&copy; 2020, </my-company>

But if I then add custom content to the Custom Element via the Shadow Dom...

class myCompany_Element extends HTMLElement {

  constructor() {
    super();
    this.root = this.attachShadow({mode: "open"});
  }

  connectedCallback() {

    this.root.textContent += 'Cyberdyne Systems';
  }
}

customElements.define('my-company', myCompany_Element);
<my-company>&copy; 2020, </my-company>

the original hard-coded content disappears. (Even though it's still visible in the DOM Inspector.)

I was expecting:

© 2020, Cyberdyne Systems

What's happening here?

Does this mean it's not possible to have

  • a Custom Element with and without Shadow DOM

and that I can only have either:

  • a Custom Element without Shadow DOM
  • a Custom Element with Shadow DOM and slots

Or is it possible to have a Custom Element with and without Shadow DOM?


Solution

  • Here's a simple solution for your use case that doesn't require slots:

    class myCompany_Element extends HTMLElement {
        constructor() {
            super()
            this.root = this.attachShadow({ mode: 'open' })
        }
    
        connectedCallback() {
            // added line below
            this.root.textContent += this.textContent
            this.root.textContent += 'Cyberdyne Systems'
        }
    }
    
    customElements.define('my-company', myCompany_Element)
    <my-company>&copy; 2020, </my-company>

    If you wanted, you could also zero out this.textContent to '' after setting this.root.textContent. As far as I can tell using Chrome dev tools, doing so makes no difference to accessibility, but might be desirable from a developer experience point of view.