Loading...
Loading...
How to correctly insert overlay elements when the host is slotted inside a shadow DOM. Covers the parentElement trap, assignedSlot pattern, and the connectedCallback timing hazard. Use when inserting overlays, portals, or absolutely-positioned siblings of slotted elements.
npx skill4agent add editframe/skills shadow-dom-overlay-insertionthis.parentElement.appendChild(overlay)EFWorkbench (shadow host)
shadow root
<div class="canvas-slot-container"> ← the real DOM parent
<slot name="canvas"> ← slot element
[EFCanvas is assigned here] ← light DOM, assigned via slotefCanvas.parentElementshadowHost.appendChild(overlay)private insertOverlay(overlay: HTMLElement): void {
const slot = this.assignedSlot;
if (slot) {
// Correctly slotted: insert into the shadow-internal container
slot.parentElement?.appendChild(overlay);
return;
}
if (this.parentElement?.shadowRoot) {
// Shadow DOM exists but slot assignment hasn't happened yet
// (connectedCallback fires before Lit renders shadow DOM).
// Return early; caller should retry via requestAnimationFrame.
return;
}
// Not slotted — plain DOM, safe to use parentElement
this.parentElement?.appendChild(overlay);
}connectedCallbackthis.assignedSlotnullthis.parentElementthis.parentElement.shadowRootperformUpdatethis.assignedSlot<slot>slot.parentElementconnectedCallback() {
super.connectedCallback();
this.tryInsertOverlay();
}
private tryInsertOverlay(): void {
if (!this.assignedSlot && this.parentElement?.shadowRoot) {
// Too early — shadow host exists but slot not yet assigned.
// Lit will assign the slot after performUpdate.
requestAnimationFrame(() => this.tryInsertOverlay());
return;
}
this.insertOverlay(this.overlay);
}| Situation | | | Action |
|---|---|---|---|
| Not slotted | null | null/undefined | Use |
| Correctly slotted | non-null | (any) | Use |
| Too early (Lit not rendered) | null | non-null | Return early, retry via RAF |
| Slotted, parent has no shadow | null | null | Use |
this.parentElement