I'm trying to move a child of a shadow dom of a web component outside it, and has been able to do it if that child has not slots inside.
Let me ilustrate with an example. I have the following 2 web components:
customElements.define('a-child', class extends HTMLElement {
constructor() {
super()
this.attachShadow({mode: 'open'})
this.shadowRoot.innerHTML = `
<slot></slot>
`
}
})
customElements.define('a-parent', class extends HTMLElement {
constructor() {
super()
this.attachShadow({mode: 'open'})
this.shadowRoot.innerHTML = `
<slot name="outside"></slot>
<a-child id=child>
<div>
<slot name="inside"></slot>
</div>
</a-child>
`
}
move() {
const child = this.shadowRoot.getElementById('child')
document.body.append(child)
}
})
And if I have the following HTML, I get what I want: even when slot inside
is inside the a-child
component in the Shadow DOM from a-parent
, it shows up correctly.
<a-parent id="parent">
<div slot="outside">outside</div>
<div slot="inside">inside</div>
</a-parent>
If I run the method move
from element with Id parent
, the a-child
element is moved to the body and I was expecting to see the div with text inside
in the body, but it doesn't happen. It seems that the slots only work when they are inside their web component.
My question is, is it possible to move a child of a Shadow DOM containing slots, outside of its web component parent?
You are right. Slots only work when they are inside their enclosing Web Components. In other words, the slots should be physically present in the DOM tree under the web component node.
Further, it is possible to move the children of Shadow DOM but if they contain slots, then it won't work. It will just fail silently without any errors.
That is one of the reasons why it is annoying. Read more for similar question. Also, this twitter thread contains some more related information. In summary, you need to move slot elements outside the component for achieving perfect stacking context for creating components like dialogs, menus, drop-downs, etc.