svelte icon indicating copy to clipboard operation
svelte copied to clipboard

<svelte:webcomponent> to create a special place for webcomponents in Svelte - but with severe limitations

Open Tommertom opened this issue 3 years ago • 0 comments

Describe the problem

I'm not frustrated with Svelte - it brings lots of fun. :)

But I do would like to see a solution to my tries to create svelte components for a webcomponent library where I am able to use the same DX for styling these as I would for regular DOM elements (in style part, with encapsulation)

I would like to create these svelte wrappers in order to solve for a number of other issues with webcomponents in svelte. One at least being that binding of values are not working. This I can solve with an dispatcher and export let.

Next, I can create nice typings this way (even though that can also be done in a different way via *.d.ts)

Describe the proposed solution

As a very bold idea I would like to propose a new directive called <svelte:webcomponent>. This directive would allow the svelte component containing it to have it's parents styles directly injected as if those were defined to itself.

Because this idea fully goes against the whole idea of encapsulation - and probably is not considered as a very pretty idea - there should be a punishment for each svelte component that uses this.

  • the component cannot define own styles
  • the component may have all sorts of script code, but operators like bind:this
  • the template part of the component may only contain 1 dom element (webcomponent ideally) and named slots, nothing more, nothing less
  • the directive will allow binding of events and props, transitions and use (maybe more?)

Pseudo code:

Parent.svelte

<script>
import SpecialChild from ...
</script>

<SpecialChild fill="outline">Some content</SpecialChild>

<style>

ion-button {
 --background:red;
}
</style>

SpecialChild.svelte

<script>
export let fill="outlined" | "block" = undefined
</script>

<svelte:webcomponent>
<ion-button {fill}><slot></ion-button>
</svelte:webcomponent>

Will render a button with a red background given the style defined in Parent.svelte.

I guess this solution will create a warning about unused styles in Parent. So that makes it also less elegant.

My thinking is - while webcomponents may or may not be fully liked by many svelte developers, they have a place in the ecosystem. By creating some sort of special place for them (behind "bars"), the sveltecompiler can deal with them separately without breaking many APIs that makes Svelte what it is is.

So, my assumption is also that this will help enlarging ecosystem for svelte by allowing people to port/embed webcomponent libraries into Svelte.

Hope this makes sense.

Alternatives considered

  1. Not making svelte wrappers, but using webcomponents directly (with or without type definitions) Then I cannot fix the binding problem. And maybe a bit more compatibility things? And tree-shaking goes away.

  2. Realising a wrapper that takes a "style" prop which contains the css. The Svelte wrapper then uses that content to apply styles to the DOM element. This seems to me a bit clunky DX, as I need to create a different API for applying style, where the encapsulated way is already great.

  3. Putting the component's specific styles in the global style definition That imho makes the whole styling a horror as I then need to manage namespaces etc. Which we wanted to get rid of with encapsulation in the first place.

Other alternatives that have been proposed in a more generic way are related to the topic style inheritance, access to parents' style, parents access childs' style,etc. For reasons I understand those have been rejected (I couldn't find the issues anymore, but there are some raised).

Happy to start drawing an RFC or so, but let's try to pass this stagegate first

Thx for your great work!

Importance

would make my life easier

Tommertom avatar Dec 02 '22 22:12 Tommertom