-
-
Notifications
You must be signed in to change notification settings - Fork 18
/
index.html
399 lines (327 loc) · 17.5 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
---
layout: layout.html
title: Islands
---
<h1><a href="/">is-land</a></h1>
<p>A new performance-focused way to add interactive client-side components to your web site.</p>
<p>Or, more technically: a framework independent partial hydration islands architecture implementation.</p>
<ul>
<li>See the <a href="https://github.com/11ty/is-land">source code on GitHub</a></li>
<li>Check out the <a href="https://youtu.be/YYJpFdEaAuc?t=188">screencast on Eleventy’s YouTube channel</a></li>
<li><a href="https://jasonformat.com/islands-architecture/">Learn more about Islands Architecture</a></li>
</ul>
<p>Features:</p>
<ul>
<li>Easy to add to existing components</li>
<li>Zero dependencies</li>
<li>Small footprint</li>
<li>Not tightly coupled to a server framework or site generator tool.</li>
<li>Server-rendering (SSR) component examples available for SSR-friendly frameworks (Lit, Svelte, Vue, and Preact are provided)</li>
</ul>
<p>Integrations in the wild:</p>
<ul>
<li><a href="https://is-land.11ty.dev/">Eleventy</a></li>
<li><a href="https://demo-webc-image-compare.netlify.app">WebC</a></li>
<li><a href="https://twitter.com/slinkitydotdev/status/1544322804774064133">Slinkity</a></li>
<li><a href="https://twitter.com/geoffrich_/status/1576932300960342018">SvelteKit</a></li>
<li><a href="https://twitter.com/jaredcwhite/status/1585433466770173953">Bridgetown</a></li>
<li><a href="https://twitter.com/techytacos/status/1590248099297259520">Lit</a></li>
<!-- <li><a href="https://techhub.social/@develwithoutacause/109332565955255126">Angular</a> (-ish?)</li> -->
</ul>
<p>Examples:</p>
<ul class="examples">
<li><img src="https://v1.indieweb-avatar.11ty.dev/https%3A%2F%2Fweb-components-cg.netlify.app%2F/" alt="The unofficial logo for web components" width="28" height="28" decoding="async" loading="lazy">Web Components (on this page)</li>
<li><img src="https://v1.indieweb-avatar.11ty.dev/https%3A%2F%2Fweb-components-cg.netlify.app%2F/" alt="The unofficial logo for web components" width="28" height="28" decoding="async" loading="lazy"><a href="demo-declarative-shadow-dom.html">Web Components using Declarative Shadow DOM</a> <em>(New in v3.0.0)</em></li>
<li><a href="demo-svelte.html"><img src="https://v1.indieweb-avatar.11ty.dev/https%3A%2F%2Fsvelte.dev%2F/" alt="IndieWeb avatar for https://svelte.dev/" width="28" height="28" decoding="async" loading="lazy">Svelte</a> (and SSR)</li>
<li><a href="demo-vue.html"><img src="https://v1.indieweb-avatar.11ty.dev/https%3A%2F%2Fvuejs.org%2F/" alt="IndieWeb avatar for https://vuejs.org/" width="28" height="28" decoding="async" loading="lazy">Vue (and petite-vue)</a> (and SSR)</li>
<li><a href="demo-preact.html"><img src="https://v1.indieweb-avatar.11ty.dev/https%3A%2F%2Fpreactjs.com%2F/" alt="IndieWeb avatar for https://preactjs.com/" width="28" height="28" decoding="async" loading="lazy">Preact</a> (and SSR)</li>
<li><a href="demo-lit.html"><img src="https://v1.indieweb-avatar.11ty.dev/https%3A%2F%2Flit.dev%2F/" alt="IndieWeb avatar for https://lit.dev/" width="28" height="28" decoding="async" loading="lazy">Lit</a> (and SSR)</li>
<li><a href="demo-alpine.html"><img src="https://v1.indieweb-avatar.11ty.dev/https%3A%2F%2Falpinejs.dev%2F/" alt="IndieWeb avatar for https://alpinejs.dev/" width="28" height="28" decoding="async" loading="lazy">Alpine.js</a></li>
<li><a href="demo-markdown.html">Embedded in <img src="https://v1.indieweb-avatar.11ty.dev/https%3A%2F%2Fwww.markdownguide.org%2F/" alt="IndieWeb avatar for https://www.markdownguide.org/" width="28" height="28" decoding="async" loading="lazy">Markdown</a></li>
<li><a href="demo-defer-hydration.html"><code>defer-hydration</code> Component Attribute Support</a> <em>(New in v3.0.0)</em> <a href="https://www.zachleat.com/web/defer-hydration/">Read more about `defer-hydration` at zachleat.com</a></li>
<li><em>Experimental:</em> <a href="demo-image-loading.html">Image Loading</a></li>
<li><em>Experimental:</em> <a href="demo-importmaps.html">Using import maps to simplify import URLs</a>. This is for-future-reference when <a href="https://caniuse.com/import-maps">browser support broadens</a>.</li>
<li><em>Test:</em> <a href="demo-stress-test.html">Stress test of 10000 islands</a></li>
</ul>
<h2>Standalone</h2>
<p>This is a control to make sure the component initializes as expected without an island.</p>
<vanilla-web-component class="demo-component">Vanilla web component</vanilla-web-component>
<h2>Defaults</h2>
<p>These islands are eagerly loaded and initialized.</p>
<is-land>
<vanilla-web-component class="demo-component">Vanilla web component</vanilla-web-component>
</is-land>
<p>Gnarly nesting</p>
<is-land>
<vanilla-web-component class="demo-component" custom-attribute some other attributes>
Vanilla web component 1a
<vanilla-web-component class="demo-component">Vanilla web component 1b</vanilla-web-component>
Vanilla web component 1c
<vanilla-web-component class="demo-component">Vanilla web component 1d</vanilla-web-component>
</vanilla-web-component>
<p>Testing A</p>
<vanilla-web-component class="demo-component">Vanilla web component 2</vanilla-web-component>
<p>Testing B</p>
<vanilla-web-component class="demo-component">Vanilla web component 3</vanilla-web-component>
</is-land>
<h2>Scroll down</h2>
<hr style="height: 100vh">
<h2><code>on:visible</code></h2>
<is-land on:visible>
<vanilla-web-component class="demo-component">Vanilla web component</vanilla-web-component>
</is-land>
<h3>Works with <details></h3>
<details>
<summary>The child content in this <details> will not be initialized until you open it</summary>
<is-land on:visible>
<vanilla-web-component class="demo-component">Vanilla web component</vanilla-web-component>
</is-land>
</details>
<h2><code>on:visible</code> nested group</h2>
<p>Parent island has <code>on:visible</code> but none of the child components have an explicit loading condition. They will inherit the loading conditions of all of the ancestors.</p>
<is-land on:visible>
<vanilla-web-component class="demo-component">Vanilla web component</vanilla-web-component>
Here’s a nested island:
<is-land autoinit="petite-vue" import="https://unpkg.com/petite-vue@0.4.1/dist/petite-vue.es.js" v-scope="{ count: 0 }">
Petite Vue
<template data-island>
<button @click="count++">⬆️</button>
<button @click="count--">⬇️</button>
<span v-html="count">0</span>
</template>
</is-land>
</is-land>
<h2><code>on:idle</code></h2>
<is-land on:idle>
<vanilla-web-component class="demo-component">Vanilla web component</vanilla-web-component>
</is-land>
<is-land on:idle>
<vanilla-web-component class="demo-component">Vanilla web component</vanilla-web-component>
</is-land>
<is-land on:idle>
<vanilla-web-component class="demo-component">Vanilla web component</vanilla-web-component>
</is-land>
<is-land on:idle>
<vanilla-web-component class="demo-component">Vanilla web component</vanilla-web-component>
</is-land>
<is-land on:idle>
<vanilla-web-component class="demo-component">Vanilla web component</vanilla-web-component>
</is-land>
<is-land on:idle>
<vanilla-web-component class="demo-component">Vanilla web component</vanilla-web-component>
</is-land>
<is-land on:idle>
<vanilla-web-component class="demo-component">Vanilla web component</vanilla-web-component>
</is-land>
<is-land on:idle>
<vanilla-web-component class="demo-component">Vanilla web component</vanilla-web-component>
</is-land>
<is-land on:idle>
<vanilla-web-component class="demo-component">Vanilla web component</vanilla-web-component>
</is-land>
<is-land on:idle>
<vanilla-web-component class="demo-component">Vanilla web component</vanilla-web-component>
</is-land>
<h2><code>on:interaction</code></h2>
<p>Requires one of: touchstart, click.</p>
<p>Note here that we used one parent island to group both of these components, and interacting with either initializes the whole group.</p>
<is-land on:interaction>
<is-land autoinit="petite-vue" import="https://unpkg.com/petite-vue@0.4.1/dist/petite-vue.es.js" v-scope="{ count: 0 }">
Petite Vue
<template data-island>
<button @click="count++">⬆️</button>
<button @click="count--">⬇️</button>
<span v-html="count">0</span>
</template>
</is-land>
<vanilla-web-component class="demo-component">Vanilla web component</vanilla-web-component>
</is-land>
<p>Use <code>on:interaction="mouseenter,focusin"</code> to override the events.</p>
<is-land on:interaction="mouseenter,focusin">
<is-land autoinit="petite-vue" import="https://unpkg.com/petite-vue@0.4.1/dist/petite-vue.es.js" v-scope="{ count: 0 }">
Petite Vue
<template data-island>
<button @click="count++">⬆️</button>
<button @click="count--">⬇️</button>
<span v-html="count">0</span>
</template>
</is-land>
<vanilla-web-component class="demo-component">Vanilla web component</vanilla-web-component>
</is-land>
<p>In this example we use a third party web component (<a href="https://github.com/zachleat/details-utils"><details-utils></a>) without any code changes made to the component. Note that children here are maintained before and after initialization (e.g. click the summary to expand before init and it keeps that state after init).</p>
<is-land on:interaction import="./lib/details-utils.js">
<button type="button" onclick="console.log('Click test')">Click test (log to console)</button>
<details-utils close-click-outside>
<details open>
<summary>Toggle Menu (Default open: click outside to close after island initializes)</summary>
<p>Note that interacting with content inside of the menu works without closing the menu.</p>
</details>
<details>
<summary>Toggle Menu (Default closed: will toggle before island initializes)</summary>
<p>Note that interacting with content inside of the menu works without closing the menu.</p>
</details>
</details-utils>
</is-land>
<h2><code>on:media</code></h2>
<h3>Viewport size</h3>
<p><code>on:media="(min-width: 64em)"</code></p>
<p>This only runs when the viewport is greater than or equal to 1024px wide: <code>on:media="(min-width: 64em)"</code></p>
<is-land on:media="(min-width: 64em)">
<vanilla-web-component class="demo-component">Vanilla web component</vanilla-web-component>
</is-land>
<p>This only runs when the viewport is less than 1024px wide: <code>on:media="(max-width: 63.9375em)"</code></p>
<is-land on:media="(max-width: 63.9375em)">
<vanilla-web-component class="demo-component">Vanilla web component</vanilla-web-component>
</is-land>
<h3>Reduced Motion</h3>
<p>This runs when the user prefers reduced motion: <code>on:media="(prefers-reduced-motion)"</code></p>
<is-land on:media="(prefers-reduced-motion)">
<vanilla-web-component class="demo-component">Vanilla web component</vanilla-web-component>
</is-land>
<p>This runs when does not have a reduced motion preference: <code>on:media="(prefers-reduced-motion: no-preference)"</code></p>
<is-land on:media="(prefers-reduced-motion: no-preference)">
<vanilla-web-component class="demo-component">Vanilla web component</vanilla-web-component>
</is-land>
<h2><code>on:save-data</code></h2>
<p>This runs when the user has <a href="https://developer.mozilla.org/en-US/docs/Web/API/NetworkInformation/saveData">Save Data</a> enabled:</p>
<is-land on:save-data>
<vanilla-web-component class="demo-component">Vanilla web component</vanilla-web-component>
</is-land>
<p><code>on:save-data="false"</code> This runs when the user does not have <a href="https://developer.mozilla.org/en-US/docs/Web/API/NetworkInformation/saveData">Save Data</a> enabled:</p>
<is-land on:save-data="false">
<vanilla-web-component class="demo-component">Vanilla web component</vanilla-web-component>
</is-land>
<h2>Controlling fallback content</h2>
<p>If you put child content in a <template> it will be JavaScript-only (no fallback). Use this to your advantage! You can mix and match <template> with other progressively enhanced content in the island.</p>
<is-land on:interaction>
<form>
<button type="button">Hydrate the island</button>
</form>
<vanilla-web-component class="demo-component">Vanilla web component (JS not required for fallback content)</vanilla-web-component>
<template data-island>
These are nested in a <template>:
<vanilla-web-component class="demo-component">Vanilla web component (JS is required for fallback)</vanilla-web-component>
<is-land autoinit="petite-vue" import="https://unpkg.com/petite-vue@0.4.1/dist/petite-vue.es.js" v-scope="{ count: 0 }">
Petite Vue (JS is required for fallback):
<template data-island>
<button @click="count++">⬆️</button>
<button @click="count--">⬇️</button>
<span v-html="count">0</span>
</template>
</is-land>
</template>
</is-land>
<p>Use the <code>ready</code> attribute on <code><is-land></code> (added when the island is hydrated) for additional styling!</p>
<is-land on:interaction id="demo-island-ready">
<style>
#demo-island-ready[ready] {
font-weight: bold;
}
#demo-island-ready[ready] .emoji {
display: none;
}
</style>
<form>
<button type="button">Hydrate the island</button>
</form>
<vanilla-web-component class="demo-component">
When hydrated the text turns bold and the clock goes away
<span class="emoji">⏰</span>
</vanilla-web-component>
</is-land>
<p>Use <code>data-island="replace"</code> to replace the island content with the template. If more than one of these exists in an island, only the first is used.</p>
<is-land on:interaction>
<form>
<button type="button">Hydrate the island</button>
</form>
<p>This content is pre-JS. This is where your loading spinner goes 😈</p>
<template data-island="replace">
<vanilla-web-component class="demo-component">Vanilla web component (requires JS)</vanilla-web-component>
</template>
</is-land>
<p>Do you know the aspect ratio of the hydrated content? On my <a href="https://www.zachleat.com/web/eleventy-rendering-modes/">personal web site</a> I use this to hydrate a <a href="https://github.com/paulirish/lite-youtube-embed"><lite-youtube> component</a>. Works great with <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/aspect-ratio">CSS <code>aspect-ratio</code></a>!</p>
<style>
#demo-aspect-ratio {
aspect-ratio: 16/9;
max-width: 400px;
background-size: 68px 48px;
background-repeat: no-repeat;
background-position: 50% 50%;
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 68 48"><path fill="%23f00" fill-opacity="0.8" d="M66.52,7.74c-0.78-2.93-2.49-5.41-5.42-6.19C55.79,.13,34,0,34,0S12.21,.13,6.9,1.55 C3.97,2.33,2.27,4.81,1.48,7.74C0.06,13.05,0,24,0,24s0.06,10.95,1.48,16.26c0.78,2.93,2.49,5.41,5.42,6.19 C12.21,47.87,34,48,34,48s21.79-0.13,27.1-1.55c2.93-0.78,4.64-3.26,5.42-6.19C67.94,34.95,68,24,68,24S67.94,13.05,66.52,7.74z"></path><path d="M 45,24 27,14 27,34" fill="%23fff"></path></svg>');
}
#demo-aspect-ratio[ready] {
background-image: none;
}
</style>
<is-land on:interaction id="demo-aspect-ratio">
<form>
<button type="button">Hydrate the island</button>
</form>
<template data-island="replace">Your video player here.</template>
</is-land>
<h2>Custom Lazy Asset Loading</h2>
<is-land on:interaction id="script-style-loading">
<form>
<button type="button">Hydrate the island</button>
</form>
<p>Nest any inline <code><script></code>, <code><script src></code>, <code><style></code>, <code><link rel="stylesheet"></code> inside a <code><template data-island></code> to execute when conditions are met. The text will turn red when the inline CSS loads and bold when the external stylesheet loads.</p>
<is-land on:interaction>
<form>
<button type="button">Hydrate the nested island</button>
</form>
<template data-island>
<script type="module">
console.log( "Nested Inline JS executed." );
</script>
</template>
</is-land>
<template data-island>
<script type="module">
console.log( "Inline JS executed." );
</script>
<script type="module" src="./lib/js-file.js"></script>
<style>
#script-style-loading { color: red; }
</style>
<link rel="stylesheet" href="./lib/css-file.css">
</template>
</is-land>
<h2>Once per page template</h2>
<h3>Group 1</h3>
<is-land on:visible>
Each of these islands has a console.log but you should only see one.
<template data-island="once">
<script type="module">console.log( "Group 1: You should only see this once for group 1." );</script>
</template>
</is-land>
<is-land on:visible>
Each of these islands has a console.log but you should only see one.
<template data-island="once">
<script type="module">console.log( "Group 1: You should only see this once for group 1." );</script>
</template>
</is-land>
<is-land on:visible>
Each of these islands has a console.log but you should only see one.
<template data-island="once">
<script type="module">console.log( "Group 1: You should only see this once for group 1." );</script>
</template>
</is-land>
<h3>Group 2</h3>
<is-land on:visible>
Each of these islands has a console.log but you should only see one.
<template data-island="once">
<script type="module">console.log( "Group 2: You should only see this once for group 2." );</script>
</template>
</is-land>
<is-land on:visible>
Each of these islands has a console.log but you should only see one.
<template data-island="once">
<script type="module">console.log( "Group 2: You should only see this once for group 2." );</script>
</template>
</is-land>
<is-land on:visible>
Each of these islands has a console.log but you should only see one.
<template data-island="once">
<script type="module">console.log( "Group 2: You should only see this once for group 2." );</script>
</template>
</is-land>