Skip to content

Commit 759e333

Browse files
Merge pull request #18 from patricknelson/issue-10-context-support
WIP: Add support for context
2 parents 8e6e9f2 + c6994d6 commit 759e333

34 files changed

+1046
-193
lines changed

README.md

+15-16
Original file line numberDiff line numberDiff line change
@@ -4,26 +4,24 @@
44

55
![Unit Tests](https://github.com/patricknelson/svelte-retag/actions/workflows/unit-tests.yml/badge.svg)
66

7-
A web component wrapper for Svelte 3 and 4. Embeds your Svelte app or components inside custom elements using the light DOM _or_
8-
shadow DOM. Automatically forwards all slots and attributes to your Svelte app.
7+
A web component wrapper for Svelte 3 and 4. Embeds your Svelte app or components inside custom elements using the light
8+
DOM _or_ shadow DOM. Automatically forwards all slots and attributes to your Svelte app.
99

1010
**Demo:** https://svelte-retag.vercel.app/
1111

1212
## Core features
1313

14-
* 🌟 **Light DOM:** Allows you to render your Svelte components as custom elements in the light DOM as usual (without
15-
requiring use of the shadow DOM). Doing so allows you to take full advantage of global styles while still maintaining
16-
encapsulation of your component specific styles, utilizing web fonts and so on.
17-
* 🎰 **Slot Support:** Supports default and named slots in the light DOM on initial page load, including nesting.
18-
* 🏃‍♂️ **Instant:** Proactively renders the Svelte component _immediately_ into the light DOM as soon as the
19-
parser encounters the custom element while dynamically re-rendering slot content as the parser moves along. This
20-
reduces CLS (Cumulative Layout Shift) and makes it interactive more quickly _without_ having to wait for the document
21-
to finish loading. _(Note: Requires compiling to IIFE format in your rollup config.)_
22-
***Vite HMR:** Unlike Svelte, these custom elements are also compatible with Vite's HMR. It avoids the infamous
23-
error `Uncaught DOMException: Failed to execute 'define' on 'CustomElementRegistry': the name "example-component" has already been used with this registry`
24-
***Flexibility:** Allows you to use your component as you normally would within Svelte (`<ExampleComponent />`) _and_
25-
as a custom element outside of Svelte (`<example-component></example-component>`). You only need to define the
26-
components that need to be available as custom elements along with their associated tag names.
14+
* 🌟 **Light DOM:** Allows you to render your Svelte components as custom elements in the light DOM as usual.
15+
* 🎰 **Slots:** Supports default and named slots in the _light DOM_ (supports nesting).
16+
* 🧭 **Context:** Use `setContext()` and `getContext()` and just compose your components as custom elements as you
17+
normally would ([see live tab demo](https://svelte-retag.vercel.app/)). Supports nesting.
18+
***Vite HMR:** Unlike Svelte, these custom elements are also compatible with Vite's HMR. It avoids the
19+
infamous `Failed to execute 'define' on 'CustomElementRegistry'` errors.
20+
* 🏃‍♂️ **IIFE/UMD:** Supports building to `iife` and `umd` for eager rendering to the light DOM, as soon as the
21+
parser encounters the custom element. Reduces CLS (Cumulative Layout Shift), making it interactive more quickly
22+
_without_ waiting for `defer`'d scripts (such as modules).
23+
***Composability:** `svelte-retag` gives you the flexility to use your component as you normally would within Svelte
24+
_and_ as a custom element outside of Svelte (supporting both `<ExampleComponent />` and `<example-component>`).
2725
* 💼 **Portability:** Enables the freedom to utilize your Svelte components anywhere custom elements are supported,
2826
regardless of the stack (great for upgrading legacy applications).
2927

@@ -101,8 +99,9 @@ On the immediate horizon:
10199
for light DOM slots during initial parsing (see https://github.com/patricknelson/svelte-retag/issues/7)
102100
- [x] Support Lit-style lowercase props (see https://github.com/patricknelson/svelte-retag/pull/9)
103101
- [x] Svelte 4 support (tested)
102+
- [x] Support context (see https://github.com/patricknelson/svelte-retag/issues/10, PR
103+
at https://github.com/patricknelson/svelte-retag/pull/18)
104104
- [x] Add demos (see https://github.com/patricknelson/svelte-retag/issues/11)
105-
- [ ] ⏳ Support context (see https://github.com/patricknelson/svelte-retag/issues/10, PR at https://github.com/patricknelson/svelte-retag/pull/18)
106105

107106
Milestones:
108107

demo/hydratable.html

+74-13
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@
2424
CSS (for better code splitting) and restoring interactivity once assets have loaded.
2525
-->
2626

27-
<app-tag pagetitle="Module with Hydration" page="hydratable" data-svelte-retag-hydratable=""><svelte-retag><main><div class="svelte-1sneid9"><a href="https://github.com/patricknelson/svelte-retag/" target="_blank" rel="noreferrer"><img src="/assets/svelte-retag.svg" class="logo svelte-1sneid9" alt="svelte-retag logo (link to GitHub repo)"></a></div> <nav class="svelte-1sneid9">Demos:
28-
<ul class="svelte-1sneid9"><li class="svelte-1sneid9"><a href="index.html" class="svelte-1sneid9">Module</a></li><li class="svelte-1sneid9"><a href="hydratable.html" class="svelte-1sneid9 current">Module with Hydration</a></li><li class="svelte-1sneid9"><a href="iife.html" class="svelte-1sneid9">IIFE/UMD</a></li></ul></nav> <h1>Module with Hydration</h1> <svelte-retag-default>
27+
<app-tag pagetitle="Module with Hydration" page="hydratable" data-svelte-retag-hydratable=""><svelte-retag><main class="svelte-694cvq"><div class="svelte-694cvq"><a href="https://github.com/patricknelson/svelte-retag/" target="_blank" rel="noreferrer"><img src="/assets/svelte-retag.svg" class="logo svelte-694cvq" alt="svelte-retag logo (link to GitHub repo)"></a></div> <nav class="svelte-694cvq">Demos:
28+
<ul class="svelte-694cvq"><li class="svelte-694cvq"><a href="index.html" class="svelte-694cvq">Module</a></li><li class="svelte-694cvq"><a href="hydratable.html" class="svelte-694cvq current">Module with Hydration</a></li><li class="svelte-694cvq"><a href="iife.html" class="svelte-694cvq">IIFE/UMD</a></li></ul></nav> <h1>Module with Hydration</h1> <svelte-retag-default>
2929

3030
<intro-tag data-svelte-retag-hydratable=""><svelte-retag><h2>About this demo</h2> <svelte-retag-default>
3131
<p>Built with <code>es</code> format and included via <code>&lt;script type="module"&gt;</code> with
@@ -39,24 +39,85 @@
3939
the page. Interactivity is then restored to those components once modules (which are
4040
<a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script#attributes" target="_blank" rel="noopener">always
4141
deferred</a>) have finished loading.</p>
42-
</svelte-retag-default> <h2>Performance</h2> <p>You can compare performance in each demo by opening DevTools, disabling cache, and then enabling network throttling
43-
(e.g. try "Fast 3G").</p> <h2>Features</h2> <p>This demo is implemented entirely using Svelte and placed in the page as custom elements (a.k.a. "web components")
44-
using <code>svelte-retag</code>. It demonstrates:</p> <ul><li>Slots (default and named slots)</li> <li>Nesting within slots</li> <li>The differences between deferred Modules and IIFE, particularly with regard to CLS (Content
45-
Layout Shift)</li> <li>Vite HMR updates (if launched locally)</li> <li>SSR/SSG + hydration <em>(experimental)</em></li></ul> <p>Note that each counter below takes an initial <code>count</code> attribute with an <code>award</code> value, at which
46-
point a 🎉 emoji is first displayed (with randomized emojis after that). Press <code>+</code> or <code>-</code> keys on
47-
your keyboard to quickly increase/decrease the count.</p></svelte-retag></intro-tag>
42+
</svelte-retag-default></svelte-retag></intro-tag>
4843

49-
<example-tag data-svelte-retag-hydratable=""><svelte-retag><div class="wrapper svelte-15rtm5g"><div class="title svelte-15rtm5g"><p slot="title" data-svelte-retag-slot="">Default: Count starts at 0, award at 100.</p></div> <div class="content svelte-15rtm5g"><counter-tag slot="content" data-svelte-retag-slot="" data-svelte-retag-hydratable=""><svelte-retag><button title="Tip: Press + or - while focused on this button." class="svelte-1cko5ar"><img src="/assets/svelte.svg" alt="svelte logo" class="svelte-1cko5ar"> Count is 0 </button></svelte-retag></counter-tag></div></div></svelte-retag></example-tag>
44+
<!-- Top level context (starts at tabs-wrapper) -->
45+
<tabs-wrapper data-svelte-retag-hydratable=""><svelte-retag><div class="tabs"><svelte-retag-default>
46+
<tab-list data-svelte-retag-hydratable=""><svelte-retag><div class="tab-list svelte-17j5wzr"><svelte-retag-default>
47+
<tab-button data-svelte-retag-hydratable=""><svelte-retag><button class="svelte-11iebyy selected"><span class="svelte-11iebyy"><svelte-retag-default>Features</svelte-retag-default></span></button></svelte-retag></tab-button>
48+
<tab-button data-svelte-retag-hydratable=""><svelte-retag><button class="svelte-11iebyy"><span class="svelte-11iebyy"><svelte-retag-default>Examples</svelte-retag-default></span></button></svelte-retag></tab-button>
49+
</svelte-retag-default></div></svelte-retag></tab-list>
5050

51-
<example-tag data-svelte-retag-hydratable=""><svelte-retag><div class="wrapper svelte-15rtm5g"><div class="title svelte-15rtm5g"><p slot="title" data-svelte-retag-slot="">Start out just 1 click away from the "award".</p></div> <div class="content svelte-15rtm5g"><counter-tag slot="content" count="99" data-svelte-retag-slot="" data-svelte-retag-hydratable=""><svelte-retag><button title="Tip: Press + or - while focused on this button." class="svelte-1cko5ar"><img src="/assets/svelte.svg" alt="svelte logo" class="svelte-1cko5ar"> Count is 99 </button></svelte-retag></counter-tag></div></div></svelte-retag></example-tag>
51+
<!-- Features -->
52+
<tab-panel data-svelte-retag-hydratable=""><svelte-retag><div class="svelte-1xkiur0 active"><svelte-retag-default>
53+
<features-info data-svelte-retag-hydratable=""><svelte-retag><p>View the
54+
<a href="https://github.com/patricknelson/svelte-retag/blob/main/demo/index.html" target="_blank" rel="noopener">page
55+
source 🚀</a>. This demo is implemented entirely using via <code>svelte-retag</code> with all Svelte components
56+
organized on the page using custom elements (or “web components”). Featuring:</p> <ul><li><strong>Slots</strong> (default and named slots)</li> <li><strong>Nesting</strong> within slots</li> <li><strong>Context</strong> (including nested context, see “Examples” tab)</li> <li><strong>Vite HMR updates</strong> (if launched locally)</li> <li>SSR/SSG via <strong>hydration</strong> <em>(experimental)</em></li></ul> <h3>Performance</h3> <p>This demo also shows the differences between deferred Modules and IIFE, particularly with regard to CLS (Cumulative
57+
Layout Shift). Use the <strong>Demos</strong> navigation above and compare each one by opening DevTools, disabling
58+
cache, and then enabling network throttling (e.g. try "Fast 3G").</p></svelte-retag></features-info>
59+
</svelte-retag-default></div></svelte-retag></tab-panel>
5260

53-
<example-tag data-svelte-retag-hydratable=""><svelte-retag><div class="wrapper svelte-15rtm5g"><div class="title svelte-15rtm5g"><p slot="title" data-svelte-retag-slot="">1337 award</p></div> <div class="content svelte-15rtm5g"><counter-tag slot="content" count="1337" award="1337" data-svelte-retag-slot="" data-svelte-retag-hydratable=""><svelte-retag><button title="Tip: Press + or - while focused on this button." class="svelte-1cko5ar"><img src="/assets/svelte.svg" alt="svelte logo" class="svelte-1cko5ar"> Count is 1337 🎉</button></svelte-retag></counter-tag></div></div></svelte-retag></example-tag>
5461

55-
<example-tag data-svelte-retag-hydratable=""><svelte-retag><div class="wrapper svelte-15rtm5g"><div class="title svelte-15rtm5g"><p slot="title" data-svelte-retag-slot="">Nested slot: "Total is"</p></div> <div class="content svelte-15rtm5g"><counter-tag slot="content" data-svelte-retag-slot="" data-svelte-retag-hydratable=""><svelte-retag><button title="Tip: Press + or - while focused on this button." class="svelte-1cko5ar"><img src="/assets/svelte.svg" alt="svelte logo" class="svelte-1cko5ar"> <svelte-retag-default>Total is</svelte-retag-default> 0 </button></svelte-retag></counter-tag></div></div></svelte-retag></example-tag>
62+
<!-- Examples -->
63+
<tab-panel data-svelte-retag-hydratable=""><svelte-retag><div class="svelte-1xkiur0"><svelte-retag-default>
64+
65+
<!-- Nested context -->
66+
<tabs-wrapper data-svelte-retag-hydratable=""><svelte-retag><div class="tabs"><svelte-retag-default>
67+
68+
<tab-list data-svelte-retag-hydratable=""><svelte-retag><div class="tab-list svelte-17j5wzr"><svelte-retag-default>
69+
<tab-button data-svelte-retag-hydratable=""><svelte-retag><button class="svelte-11iebyy selected"><span class="svelte-11iebyy"><svelte-retag-default>Slots and Attributes</svelte-retag-default></span></button></svelte-retag></tab-button>
70+
<tab-button data-svelte-retag-hydratable=""><svelte-retag><button class="svelte-11iebyy"><span class="svelte-11iebyy"><svelte-retag-default>Nested Context Support</svelte-retag-default></span></button></svelte-retag></tab-button>
71+
</svelte-retag-default></div></svelte-retag></tab-list>
72+
73+
<!-- Slots and Attributes -->
74+
<tab-panel data-svelte-retag-hydratable=""><svelte-retag><div class="svelte-1xkiur0 active"><svelte-retag-default>
75+
<examples-info data-svelte-retag-hydratable=""><svelte-retag><p>All element attributes in <em>this particular</em> demo are configured to be dynamic. Try editing the
76+
<code>pagetitle</code> in <code>&lt;app-tag pagetitle="..."&gt;</code> above or any of the
77+
<code>count</code> or <code>award</code> attributes in any of the <code>&lt;counter-tag&gt;</code> buttons below.</p> <p>For example: Each counter below takes an initial <code>count</code> attribute with an <code>award</code>
78+
value, at which point a 🎉 emoji is first displayed (with randomized emojis after that). Press <code>+</code> or <code>-</code>
79+
keys on your keyboard to quickly increase/decrease the count.</p></svelte-retag></examples-info>
80+
81+
<example-tag data-svelte-retag-hydratable=""><svelte-retag><div class="wrapper svelte-15rtm5g"><div class="title svelte-15rtm5g"><p slot="title" data-svelte-retag-slot="">Default: <code>count</code> starts at 0, <code>award</code> at 100.</p></div> <div class="content svelte-15rtm5g"><counter-tag slot="content" data-svelte-retag-slot="" data-svelte-retag-hydratable=""><svelte-retag><button title="Tip: Press + or - while focused on this button." class="svelte-14anzuk"><img src="/assets/svelte.svg" alt="svelte logo" class="svelte-14anzuk"> Count is 0 </button></svelte-retag></counter-tag></div></div></svelte-retag></example-tag>
82+
83+
<example-tag data-svelte-retag-hydratable=""><svelte-retag><div class="wrapper svelte-15rtm5g"><div class="title svelte-15rtm5g"><p slot="title" data-svelte-retag-slot="">Start out just 1 click away from the <code>award</code>.</p></div> <div class="content svelte-15rtm5g"><counter-tag slot="content" count="99" data-svelte-retag-slot="" data-svelte-retag-hydratable=""><svelte-retag><button title="Tip: Press + or - while focused on this button." class="svelte-14anzuk"><img src="/assets/svelte.svg" alt="svelte logo" class="svelte-14anzuk"> Count is 99 </button></svelte-retag></counter-tag></div></div></svelte-retag></example-tag>
84+
85+
<example-tag data-svelte-retag-hydratable=""><svelte-retag><div class="wrapper svelte-15rtm5g"><div class="title svelte-15rtm5g"><p slot="title" data-svelte-retag-slot="">1337 <code>award</code></p></div> <div class="content svelte-15rtm5g"><counter-tag slot="content" count="1337" award="1337" data-svelte-retag-slot="" data-svelte-retag-hydratable=""><svelte-retag><button title="Tip: Press + or - while focused on this button." class="svelte-14anzuk"><img src="/assets/svelte.svg" alt="svelte logo" class="svelte-14anzuk"> Count is 1337 🎉</button></svelte-retag></counter-tag></div></div></svelte-retag></example-tag>
86+
87+
<example-tag data-svelte-retag-hydratable=""><svelte-retag><div class="wrapper svelte-15rtm5g"><div class="title svelte-15rtm5g"><p slot="title" data-svelte-retag-slot="">Slot: "Total is"</p></div> <div class="content svelte-15rtm5g"><counter-tag slot="content" data-svelte-retag-slot="" data-svelte-retag-hydratable=""><svelte-retag><button title="Tip: Press + or - while focused on this button." class="svelte-14anzuk"><img src="/assets/svelte.svg" alt="svelte logo" class="svelte-14anzuk"> <svelte-retag-default>Total is</svelte-retag-default> 0 </button></svelte-retag></counter-tag></div></div></svelte-retag></example-tag>
88+
</svelte-retag-default></div></svelte-retag></tab-panel>
89+
90+
<!-- Nested Context Support -->
91+
<tab-panel data-svelte-retag-hydratable=""><svelte-retag><div class="svelte-1xkiur0"><svelte-retag-default>
92+
<tabs-info data-svelte-retag-hydratable=""><svelte-retag><p>Credit to <a href="https://stackoverflow.com/users/1990514/amir-pournasserian" target="_blank" rel="noopener">AmirPournasserian</a>
93+
from
94+
<a href="https://stackoverflow.com/questions/75024281/how-to-avoid-overwriting-context-in-nested-components-like-tabs-in-svelte" target="_blank" rel="noopener">this StackOverflow post</a> for the original <code>.svelte</code> components which were then converted to custom
95+
elements using <code>svelte-retag</code> to help demonstrate context. These are implemented purely by arranging the
96+
following tags using only HTML and <em>can even be nested</em>, just like in this demo!</p> <pre>&lt;tabs-wrapper&gt;
97+
&lt;tab-list&gt;
98+
&lt;tab-button&gt;Tab 1&lt;/tab-button&gt;
99+
&lt;tab-button&gt;Tab 2&lt;/tab-button&gt;
100+
&lt;/tab-list&gt;
101+
102+
&lt;tab-panel&gt;
103+
&lt;!-- Content for Tab 1 --&gt;
104+
&lt;/tab-panel&gt;
105+
106+
&lt;tab-panel&gt;
107+
&lt;!-- Content for Tab 2 --&gt;
108+
&lt;/tab-panel&gt;
109+
&lt;/tabs-wrapper&gt;
110+
</pre> <p>In this example, <code>&lt;tabs-wrapper&gt;</code> defines the shared context and <code>&lt;tab-button&gt;</code>
111+
toggles between each <code>&lt;tab-panel&gt;</code> within that context.</p> <p></p></svelte-retag></tabs-info>
112+
</svelte-retag-default></div></svelte-retag></tab-panel>
113+
</svelte-retag-default></div></svelte-retag></tabs-wrapper>
114+
115+
</svelte-retag-default></div></svelte-retag></tab-panel>
116+
117+
</svelte-retag-default></div></svelte-retag></tabs-wrapper>
56118

57119
</svelte-retag-default></main></svelte-retag></app-tag>
58120

59121
</div>
60-
61122
</body>
62123
</html>

0 commit comments

Comments
 (0)