Description
Describe the problem
Since slots are already supported when compiling to custom elements (via shadow DOM) and Svelte can now natively utilize the light DOM (thanks to #8457), one might naturally also want slot support when in the light DOM. This is not currently possible, but would be awesome if Svelte had a way of natively supporting slot content when not using a shadow root.
For example, given ExampleElement.svelte
:
<svelte:options
customElement={{
tag: 'example-element',
shadow: 'none',
}}
/>
<h1>My Heading</h1>
<slot/>
And index.html
containing:
<example-element>
<p>Hello world!</p>
</example-element>
The final rendered version in the light DOM might look something like this:
<example-element>
<h1>My Heading</h1>
<p>Hello world!</p>
</example-element>
Note: This is a reopening/variant of #8686 where this was originally reported as a bug.
Describe the proposed solution
Taking inspiration from experimentation already done in svelte-retag
, I'd propose two approaches, each of which are necessary depending on how the compiled component is shipped (e.g. esm
or umd
/iife
)
- Module + UMD/IIFE: Parse out elements with named
slot="..."
attributes and populate into Svelte component slots. Use remaining content as "default" content for the default slot. - UMD/IFFE only: Do the above, but also watch for changes using
MutationObserver
since the customHTMLElement
will connect early while the parser appends new nodes (i.e. slot content) as it moves across the DOM. Practically, this can be accomplished by temporarily (or permanently) isolating rendered component HTML to prevent recursion.svelte-retag
accomplishes this by tucking that HTML into a no-op custom element called<svelte-retag>
where we can be certain that rendered HTML lives in a separate hierarchy that will not be confused with newly appended child nodes as the parser progresses.
One might also want to ensure they account for changes to slot content beyond document.readyState === 'complete'
(svelte-retag
doesn't yet do this so I haven't tried it yet). But this is just one possible approach.
Alternatives considered
This concept is already readily demonstrated here in Svelte using light DOM custom elements via svelte-retag
.
Importance
would make my life easier