sveltejs / svelte

Cybernetically enhanced web apps
https://svelte.dev
MIT License
78.37k stars 4.1k forks source link

A component wrapping a custom element is not rendered into a slot correctly #7428

Closed winterkind closed 3 weeks ago

winterkind commented 2 years ago

Describe the bug

See the link to the REPL below...

I have two components, Input and Icon, which both wrap imported custom elements:

In my main component, App.svelte, I use Input.svelte twice. Both times I try to set an icon to the input by using the icon slot. When I fill the slot with ui5-icon directly, that works fine. But when I try the same with the Icon.svelte component, no icon shows.

Am I overlooking something obvious or is this a bug? From what I can see in the rendered DOM, one ui5-icon is added as a child of ui5-input in both cases. But in the second case, ui5-icon is missing the slot="icon" attribute.

Reproduction

REPL: https://svelte.dev/repl/6e8a7f1a4dc64fdba71aa72be8b17be9?version=3.46.6

Logs

No response

System Info

Svelte REPL, version 3.46.6

Severity

annoyance

abdo643-HULK commented 2 years ago

Here is a working version: https://svelte.dev/repl/e6c8287c4a454fb8b8cfa0d474a5f34d?version=3.46.6. The reason is the slot doesn't get passed on to the Icon component because you didn't declare as named slot and because the slot attribute is reserved, you need to use $$restProps to pass it to the component.

abdo643-HULK commented 2 years ago

There are an issue about slots: https://github.com/sveltejs/svelte/issues/1689

winterkind commented 2 years ago

@abdo643-HULK Thanks a lot for taking the time to find a workaround! Also thanks for pointing out the existing issue, I had overlooked that one.

I tried the workaround given in that issue, of wrapping the component in the slot inside a div. That also works.

So there is really something wrong here... Interesting to see that this is something that is over three years old. I guess not many people use custom elements inside Svelte components. Maybe even partly because of this issue.

Just one question: what do you mean by saying "because you didn't declare as named slot"? Did I forget anything?

abdo643-HULK commented 2 years ago

If svelte doesn't recognise a named slot it won't render it and that's what happend. And passing it as a prop doesn't work because the compiler will complain about slot being dynamic. There are a lot of problems around the compatibility of web-components and svelte and even other frameworks. But because svelte uses something like slot for itself, it starts to interfere with the web-components spec

dummdidumm commented 3 weeks ago

Closing because Svelte 5 replaces slots with snippets, which also solve this / make the code easier to reason about. It would become this:

<script>
    import Input from "./Input.svelte"
    import Icon from "./Icon.svelte"
    import "@ui5/webcomponents-icons/dist/search";

</script>

<Input>
       {#snippet icon()}
        <ui5-icon name="search" />
    {/snippet}
</Input>

<Input>
       {#snippet icon()}
        <Icon name="search" />
    {/snippet}
</Input>