0

I'm trying to build a WebComponent without using ShadowDOM - so far it mostly just worked, but now I want to build a component that wraps other components like you would do with Angular's @ViewChild / @ViewChildren. (the library I'm using here to render is uhtml 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 now use this component

Dropdown.register();


render(document.body, html`
    <my-dropdown open="true">
        <strong slot="item">test</strong>
    </my-dropdown>

`)

I'm expecting to see

<my-dropdown>
    <div>
        <strong>test</test>
    </div>
</my-dropdown>

but the slot part is not working.

If I switch to ShadowDOM, it just works, but now I have to deal with ShadowDOM's sandbox with regards to styling which I'd rather not do.

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 different way to grab the content defined inside the component and use it inside display?

<my-component>
    <div>some content here</div>
</my-component>

should render as

<my-component>
    <header>
        random header
    </header>
    <section>
        <!-- my custom content -->
        <div>some content here</div>
    </section>
</my-component>

Any suggestions?

Jan Vladimir Mostert
  • 12,380
  • 15
  • 80
  • 137

1 Answers1

1

No, <slot> are part of the shadowDOM API

You can fake it, but since there is no shadowDOM you would have to store that content someplace else.
Could be a <template> you read and parse your (light)DOM content into.

That is a sh*load of DOM mutations.
Might be easier to just learn to style shadowDOM with:

  • CSS properties
  • inheritable styles
  • ::part
  • constructable stylesheets
Danny '365CSI' Engelman
  • 16,526
  • 2
  • 32
  • 49
  • and the content inside that slot is changing depending on state which would make the stored content stale. Pity, I was just getting excited that I've escaped ShadowDOM and could style things globally. Guess I'll go back to ShadowDOM – Jan Vladimir Mostert Feb 04 '23 at 18:39
  • 1
    And don't forget [::slotted](https://stackoverflow.com/questions/61626493/slotted-css-selector-for-nested-children-in-shadowdom-slot/61631668#61631668) – Danny '365CSI' Engelman Feb 04 '23 at 19:44