-
-
Notifications
You must be signed in to change notification settings - Fork 4.7k
Description
Describe the problem
I work on a team partly composed of web designers (not programmers) who are mainly familiar with HTML/CSS. We want to shift to a component-based workflow and the programmers on the team would love to use Svelte over the other options available. However, we need whatever tooling we make to be as seamless, user-friendly, and HTML-like as possible for the benefit of our other team members.
This means we need to use custom elements or web components rather than raw Svelte components. Currently, if you configure a Svelte component with svelte:options customElement={{ ... }} />, there's all this scary business with props, extend and other JavaScript just dumped at the top of the file. That is a big turn off and will scare them away easily, opting them to disregard a move to web components entirely (historically speaking).
Describe the proposed solution
It would be a lot less scary if CustomElement/WebComponent options could be presented as a simple HTML element abstraction, with the host visualized directly in the markup. For example, if we added a svelte:host "special element", then something like this (from docs):
<svelte:options
customElement={{
tag: 'custom-element',
shadow: 'none',
props: {
name: { reflect: true, type: 'Number', attribute: 'element-index' }
},
extend: (customElementConstructor) => {
// Extend the class so we can let it participate in HTML forms
return class extends customElementConstructor {
static formAssociated = true;
constructor() {
super();
this.attachedInternals = this.attachInternals();
}
// Add the function here, not below in the component so that
// it's always available, not just when the inner Svelte component
// is mounted
randomIndex() {
this.elementIndex = Math.random();
}
};
}
}}
/>
<script>
export let elementIndex;
export let attachedInternals;
// ...
function check() {
attachedInternals.checkValidity();
}
</script>...could be condensed to this:
<script context="module">
import { customConstructor } from "./constructors";
</script>
<script>
export let internals;
export let host;
</script>
<!-- Two Alternative uses of svelte:host, depending on shadow="none", perhaps? -->
<!-- Custom Element w/ shadow="none" -->
<svelte:host bind:this={host} tag="custom-element" bind:attachedInternals={internals} extend={customConstructor} shadow="none" />
<!-- Web Component w/ slots, w/o shadow="none" -->
<svelte:host bind:this={host} tag="custom-element" bind:attachedInternals={internals} extend={customConstructor}>
<span><slot></slot></span>
</svelte:host>This would offer a number of advantages...
- With this simpler, declarative, and more familiar/intuitive syntax, those less experienced with programming will have a much easier time working with the tool to create or edit custom elements.
- You can now directly perceive the "host" within the markup of your component. This makes it easier to visualize the end result of what your component will be rendering in the final output.
- Because the host is now represented directly as an element, you can use
bind:thisto acquire a reference to it (or would that merely have to be an abstraction that uses the extend constructor and a hidden_hostproperty under-the-hood? idk). - Like
svelte:element, you could have special attributes for configuring it (liketag), and then allow other modifications to the element (like attributes) to seamlessly bleed through to the actual host, as if they'd been assigned during theextendconstructor.- Though, in that case, I think there'd need to be an awareness that two-way data binding would be delayed until onMount and any directly injected data would have to come from a
context="module"script rather than the Svelte component's script content since that loads after the host is created. Not too familiar with Svelte internals yet.
- Though, in that case, I think there'd need to be an awareness that two-way data binding would be delayed until onMount and any directly injected data would have to come from a
The more that the complexities of Svelte components as custom elements can be abstracted away via HTML-like markup and conventions (optionally), the easier it will be for less-experienced team members / programmers to be amenable to using the tools in the first place.
This proposal is still lacking in ways though. For example, I'm not sure yet how best to expose things like props configuration as mere attributes on the svelte:host element. Unless, say, you added a host: directive too and could then do...
<svelte:host host:elementIndex={ reflect: true, type: "Number", attribute: "element-index" } />That might pushing things too far though. Idk.
Alternatives considered
If you want to work with custom elements in Svelte, as things currently stand, the tooling is all quite raw (because it's new). There are not yet any alternatives to simplify things, unless we just abandon Svelte altogether (which the devs on my team strongly want to avoid doing)
Importance
would make my life easier