Skip to content

Generate custom elements #797

@Rich-Harris

Description

@Rich-Harris

I'd thought of this as a 'one day' feature, since custom elements aren't universally supported and we already have svelte-custom-elements. But then I started building an Electron app (where custom elements are supported), and started building a UI kit for it (because the nearest thing I could find, photonkit, appears to be abandoned and pertains to an older version of Electron), and it's one of those cases where custom elements really would be quite nice.

svelte-custom-elements sort of works, but it's suboptimal because

  • no true style encapsulation (elements aren't shielded from global styles, and you don't get the perf benefits of a local CSSOM)
  • there's no light DOM — slotted content becomes part of the shadow DOM

So I think we should add one of the following:

compiled = svelte.compile({
  customelement: true,
  name: 'x-foo'
});

compiled = svelte.compile({
  customelement: 'x-foo'
});

Maybe a component should be able to specify its own name, and customelement: true means 'use the component's self-declared name, or error if it doesn't have one', and customelement: 'x-foo' means 'register this component is <x-foo> whatever it calls itself'.

Differences in input/output that I can think of:

  • it would export a class, rather than a constructor function
  • styles wouldn't get transformed. (Not entirely sure how styles work tbh — does the <style> tag need to get attached to every single instance's shadow DOM?)
  • <slot> elements would get rendered, and options.slots would be ignored (because there would be no options)
  • attributes/props need to be part of the component definition (or compiler options, I guess, for situations where the component author didn't anticipate custom element usage)
  • fire might need to wrap dispatchEvent? Not sure if we'd want to merge on and addEventListener (i.e. mix DOM events together with component events). I think we might have to so that <my-thing on:myEvent='doSomething()'> works. I guess we'd just disable bubbling by default, so that things don't get too wacky

A few nice things that would come out of this:

  • Custom elements would still be Svelte components, so you'd still be able to use set, get, observe
  • Svelte components would be elements, so you'd be able to listen for DOM events, style them, add classes, use transitions etc without having to add wrapper elements
  • Svelte apps would be able to compile the custom elements with shared: true so there'd be very little overhead
  • Our components would be smaller (and probably faster) than Stencil's 😀

Any thoughts?

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions