Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Slotted content for Web Component nested inside of a Svelte component is not applied to the Web Component #1689

Open
nsaunders opened this issue Aug 24, 2018 · 10 comments
Labels
awaiting submitter needs a reproduction, or clarification custom element

Comments

@nsaunders
Copy link

Given a Web Component which expects slotted children, which itself is nested inside of a Svelte component, as in the following:

<SvelteComponent>
  <my-custom-element>
    <div slot="slot1">my-custom-element content</div>
    <div slot="slot2">more my-custom-element content</div>
  </my-custom-element>
</SvelteComponent>

...the slotted children are not applied to the Web Component.

I have reproduced the issue here (just run npm install and npm run build and then open dist/index.html in your browser):
https://github.com/therealnicksaunders/svelte/tree/issue/slotted-content

In a more complicated example, this actually produces an error which suggests that a slotted child is being applied to the Svelte component instead of the Web Component in which it is nested. We have this Svelte-generated code:

(0, _shared.append)(pagecontent._slotted.header, div);

The referenced div is nested inside of a Web Component; its "slot" attribute of "header" corresponds to a slot inside of that Web Component rather than the PageContent Svelte component (which has no named slots).

Hopefully I have provided enough info here... Please let me know if I can clarify anything.

Thanks in advance for your help looking into it!

@alindsay55661
Copy link

I am also experiencing this issue, Svelte is highjacking slots from HTML custom elements.

@alkismavridis
Copy link

alkismavridis commented Dec 28, 2019

Also affected. In my company, we are actually thinking of migrating big parts of our infrastructure in svelte.
But without a solution on that issue, we will not be able to use our (already developed) custom elements.
This would be a pity because svelte is a really awesome framework.
Please consider giving a proper solution, or at least a workaround on that.

Thanks in advance!

Edit:
I found a workaround using the "use:" directive and add the slot attribute manually.
This way, I can use slots within if blocks and everything. Svelte does not try to interpret it:

  <my-web-component>
    {#if showSlots}
      <div use:addNamedSlot={"subtitle"}>My subtitle</div>
      <div use:addNamedSlot={"footer"}>My footer</div>
    {/if}
  </my-web-component>

//... and my fucntion addNamedSlot:
export function addNamedSlot(node: HTMLElement, name: string) { //if you don't use ts, just remove the :Type from the params
  node.setAttribute("slot", name);
}

I actually implemented the addNamedSlot in an other file so that I can import it and re-use it.

Still, it would be very nice to have a way saying to svelte:
hey, do not try to interpret my slot tags and slot attributes, just render them as you would with any other attribute/tagname.

@E01T
Copy link

E01T commented Jan 7, 2020

A simple workaround is to put your custom component into an html element. Then the html element will target the appropriate slot. e.g.

<div slot="footer"> <!-- html element which targets the appropriate slot -->
    <Button caption="Save" /> <!-- Custom svelte component -->
</div>

@tanhauhau
Copy link
Member

@nsaunders your repro is not found https://github.com/therealnicksaunders/svelte/tree/issue/slotted-content, would it be possible to help recreate the repro so i can take a look at it?

@antony
Copy link
Member

antony commented Apr 9, 2020

Closing due to inactivity, will re-open if a repro appears.

@antony antony closed this as completed Apr 9, 2020
@RobertWeaver
Copy link

I tried to make a CodeSandBox to demonstrate this issue. I am using custom elements from Ionic.

Using an html element like span does work. However for certain other Custom Element components having this extra span tag breaks the display of the Custom Element.

Using svelte:fragment would be great but I have not found a way to get it to forward to the correct Custom Element slot.

The Ionic Toolbar component has these slots defined...
image

Ionic Toolbar Source

I have the Svelte Toolbar component configured as
image

Here is the result of my testing in the CodeSandBox. Hopefully I didn't make too many mistakes 😅

image

CodeSandBox 👨‍💻

@RobertWeaver
Copy link

Hey @tanhauhau I added an example in the above comment.

Do you think we can take a look and see if the issue can be reopened? ☺️

@tanhauhau
Copy link
Member

copied the code sandbox into https://svelte.dev/repl/cfe22283aa194419887fd45f9775a245?version=3.38.3

@Tommertom
Copy link

Tommertom commented Nov 27, 2022

Hi

using the UI5 REPL available through the mentioned link I managed to implement slot content projection (is that the proper word?) into the svelte component for Ionic components (as @RobertWeaver & @tanhauhau tried). With a few amendments. I did not use $$restProps nor svelte:fragment

This as part of the project to have all Ionic elements have Svelte wrappers (90 components).

So my understanding (and this is working in practice for me) that there are two steps here needed to realise this -

Step 1. adding the slot definitions within the <slot name="slotname"> in the component. This tells the Svelte compiler these slots are OK - but does not yet project to content into it.

Step 2. using $$props to spread the slot definition into the webcomponent.

The Svelte wrapper IonItem.svelte for webcomponent ion-item would then look like this:

<script lang="ts">
  import type { Color, AnimationBuilder, RouterDirection } from "@ionic/core";
  import { IonItem } from "@ionic/core/components/ion-item";
  import { defineComponent } from "ionic-svelte";  // code that registers the webcomponent

  //@ts-ignore
  export let color: Color = undefined;
  //@ts-ignore
  export let button = false;
 ...all sorts of props

  defineComponent("ion-item", IonItem);
</script>

<ion-item
  {color}
 ....other props
  {lines}
  {counter}
  {routerAnimation}
  {routerDirection}
  {target}
  {type}
  {counterFormatter}
  {...$$props}            // this propagates the slot names and the content
  on:focus
  on:blur
  ..... other events
  on:click
  ><slot /><slot name="start" /><slot name="end" /><slot name="error" /><slot name="helper"  />
</ion-item>

Now I don't have any issues getting the content in the right slot and no typescript issues. Here the full code for this wrapper - https://github.com/Tommertom/svelte-ionic-npm/blob/main/experimental/components/IonItem.svelte

But now there are other issues now arising, getting webcomponents to work with Svelte wrappers, as internal stuff in the webcomponent library cannot target elements properly anymore...... not sure if this is because the setup I have choosen.

ps.
The alternative I had going on earlier was using a shim property called ionSlot that would use {#if ionSlot=... blocks to hardcode slot content in the webcomponent. And then I also had to use an Empty svelte component with all slot definitions to avoid complaints from the Svelte compiler. I felt this was not the best way to go.

@patricknelson
Copy link

Potentially relates to #8457 and #3128.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
awaiting submitter needs a reproduction, or clarification custom element
Projects
None yet
Development

No branches or pull requests