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

Support nested custom elements #3520

Closed
milkbump opened this issue Sep 6, 2019 · 12 comments
Closed

Support nested custom elements #3520

milkbump opened this issue Sep 6, 2019 · 12 comments
Labels
awaiting submitter needs a reproduction, or clarification custom element

Comments

@milkbump
Copy link

milkbump commented Sep 6, 2019

Is your feature request related to a problem? Please describe.
If I have multiple levels of nested components, the components "disappear" when compiled to custom elements. I need to use custom elements for CSS encapsulation in a component that has multiple layers of svelte components.

Describe the solution you'd like

<!--Calendar.svelte-->
<div>
     <ButtonComponent/>
</div>

<!--ButtonComponent.svelte-->
<div class='button'>
     <LinkComponent/>
</div>

when exported should output

<my-calendar>
     <my-button>
          <my-link></my-link>
     </my-button>
</my-calendar>

instead of

<my-calendar>
     <div class='button'>
          <slot></slot>
     </div>
</my-calendar>

If all the nested Svelte components in the tree have the <svelte:option tag="my-component"> set.

Describe alternatives you've considered
The only alternative I've come up with is to export each component individually and then nest them elsewhere. Doing it this way beats the purpose of using Svelte and the conveniences it brings.
I have tried creating a custom element and then embedding a Svelte component inside it, but Svelte javascript inlines styles into the main document's head, and not into the shadow dom of the parent custom component, so styles are not applied to the Svelte component (This is unexpected, and I think this should be a separate issue on its own).

How important is this feature to you?
This is a very important feature. I'm working on a Chrome extension that injects a Svelte component into a range of pages, so the shadow dom is needed for CSS encapsulation. My component has other Svelte components such as Buttons etc. nested deeply inside.

This might be related to #2605

@Rich-Harris
Copy link
Member

It's possible that Svelte's behaviour should change here, but in the meantime what about doing it like this?

<!--Calendar.svelte-->
<svelte:options tag="my-calendar"/>

<script>
  import './ButtonComponent.svelte';
</script>

<div>
  <my-button/>
</div>

@milkbump
Copy link
Author

milkbump commented Sep 8, 2019

Right. Why didn't I think of that? 😅 I like this pattern better than what I was using, and will probably switch to it in for now. That said, I think that the jump from ButtonComponent to my-button is "magical" and not easily parsable to someone reading your code. Alternatively, one can take the inconvenient route in the name of readability.

<svelte:options tag="my-calendar"/>

<script>
  import ButtonComponent from './ButtonComponent.svelte';

  customElements.define("my-botton", ButtonCompontent);
</script>

<div>
  <my-button/>
</div>

Svelte can help solve this. I'm in support of writing Svelte components as Svelte components and having the compiler take care of making them custom elements under the hood if that's practically implementable. I think having it done under the hood the right kind of "magical". 🙂

@MonkeyAndres
Copy link

I just created a template for using Svelte and web components interchangeably in a codebase. And also comes with Storybook and i18n configured.
More info: https://github.com/redradix/svelte-custom-element-template

@harshvitra
Copy link

Going through the same issue.
Started Svelte for this purpose of building web component.

@milkbump
Copy link
Author

A year of Svelte later, I don't feel the same way about this feature request anymore. I prefer the current behaviour to the requested one. I now avoid custom elements like plague, but if I must, I've learnt I only need a wrapper and don't want the children to also become web components.

But there seems to be marginal interest, so I'll leave the issue open for now. Thoughts?

@antony
Copy link
Member

antony commented Jan 22, 2021

I think it's undecided if this is something that we'd want to change, and unless a community member appears and makes this change, it's unlikely to get changed anytime soon, since web components aren't really the primary focus. Happy for it to be left open or closed as people see fit.

@syffs
Copy link

syffs commented Apr 6, 2021

if I must, I've learnt I only need a wrapper and don't want the children to also become web components.

@kwangure Could you please ellaborate on this ?

@milkbump
Copy link
Author

milkbump commented Apr 6, 2021

I use the web component as a parent, and then every other component nested inside is a regular Svelte component.

<my-wrapper>
	<RegularComponent1></RegularComponent1>
	<RegularComponent2></RegularComponent2>
</my-wrapper>

I usually only reach for web components when I need to encapsulate CSS. In my example, the <my-wrapper> shadowDOM isolates the inner components from the outer DOM. Therefore RegularComponent1 and RegularComponent2 don't need to be web components themselves.

@syffs
Copy link

syffs commented Apr 7, 2021

@kwangure Interesting ! Now, how do you configure customElement build selectively ? Do you use something similar as this trick ?

@milkbump
Copy link
Author

milkbump commented Apr 7, 2021

Yes. I do exactly that.

If you're using svelte-kit see comments about setup at sveltejs/kit#773.

@syffs
Copy link

syffs commented Apr 7, 2021

Thanks for the help, I'm quite new to svelte and it's much appreciated !

I've set emitCss: false for my regular components and CSS gets inserted into my document.head instead of the shadowDOM. As a result no styling is applied to nested components:

svelte({
	preprocess:  sveltePreprocessOpts,
	include: WEB_COMPONENT_POSTFIX,
	compilerOptions: {
		customElement: true,
		...svelteCompilerOpts,
	}
}),
svelte({
	preprocess:  sveltePreprocessOpts,
	emitCss: false,
	exclude: WEB_COMPONENT_POSTFIX,
	compilerOptions: {
		customElement: false,
		...svelteCompilerOpts,
	}
}),

Is there a way to have shadowDOM <style></style> include my nested components styles ?

@milkbump
Copy link
Author

milkbump commented Apr 8, 2021

It seems like you're following the long-winded path I've gone down before.😂

I opened an issue when I first got to where you've gotten. I mention how I work around that here #4039 (comment).

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

7 participants