Svelte compiler and web components

Viewed 37

I have a simple web component written in plain Javascript. Its use:

<layer-list>
     <item color="#0069C6">Layer 1</item>
     <item color="#EF4627">Layer 2</item>
     <item color="#8F17A0">Layer 3</item>
</layer-list>

It'd manipulate its content, the items, from the constructor. It works on a plain HTML page. However placing it in a .svelte file breaks it. The Svelte compiler dissects the <item>s from the component. At the time the web component constructor (or the connectedCallback) runs it's an empty <layer-list>. Items are put back later as the bundle.js reconstructs the page.

Can I delay the construction of the web component?

Is it possible to use the component like this:

<layer-list>
     {#each layers as l}
     <item color="{l.color}">{l.name}</item>
     {/each}
</layer-list>

Thanks.

1 Answers

It's hard to say without seeing the implementation of your layer-list component, but I assume layer-list is updating some internal state based on the contents of its <slot> at construction time.

If you can modify the implementation of layer-list, you should listen to a slotchange event and run the logic you had in connectedCallback in the event handler instead. This way, when the slot content is updated your component can react accordingly.

While this is useful in the Svelte render situation where the parent is rendered before its children, it also makes your component more resilient to the contents of the slot changing (e.g. elements being added/removed).

Example (using Lit, but should be generalizable to however you build your web components):

import {html, css, LitElement} from 'lit';

export class LayerList extends LitElement {
  handleSlotChange(e) {
    console.log('current slot contents:', e.target.assignedElements());
  }
  
  render() {
    return html`<slot @slotchange=${this.handleSlotChange}></slot>`;
  }
}

customElements.define('layer-list', LayerList);
Related