I'm trying to build a WebComponent without using ShadowDOM - so far it's basically just working, but now I want to build a component that wraps other components, like using Angular's @ViewChild
/ @ViewChildren
Same. (The library I use for rendering here is uhtl, similar to lit-html)
export class Dropdown extends HTMLElement { private open: boolean = false; static observedAttributes = ["open"] constructor() { super(); } attributeChangedCallback(name: string, oldValue: string, newValue: string) { switch (name) { case "open": this.open = Boolean(newValue); break; } this.display() } connectedCallback() { this.display() } display = () => { render(this, html` <div> <slot name="item"> </slot> </div> `) } static register = () => customElements.define("my-dropdown", Dropdown) }
If I use this component now
Dropdown.register(); render(document.body, html` <my-dropdown open="true"> <strong slot="item">test</strong> </my-dropdown> `)
I look forward to seeing it
<my-dropdown> <div> <strong>test</test> </div> </my-dropdown>
But the slot part doesn't work.
If I switch to ShadowDOM it works, but now I have to deal with ShadowDOM's sandboxing and I don't want to do that.
constructor() { super(); this.attachShadow({mode: "open"}) }
display = () => { render(this.shadowRoot as Node, html`
Is it possible to make slots work without ShadowDOM? If not, is there a different way to get what is defined inside the component and use it inside the display?
<my-component> <div>some content here</div> </my-component>
should be rendered as
<my-component> <header> random header </header> <section> <!-- my custom content --> <div>some content here</div> </section> </my-component>
Any suggestions?
No,
<slot>
is part of the ShadowDOM APIYou can fake it, but since there is no shadowDOM, you have to store that content somewhere else.
Probably your
<template>
that reads and parses the (light) DOM content.This is a bunch of DOM mutations.
It might be easier to learn to use ShadowDOM styles: