Stand with Ukraine 🇺🇦
Eleventy
The possum is Eleventy’s mascot

Eleventy Documentation

Menu

Partial Hydration Coming soon in v2.0.0 Jump to heading

Expand for contents

A plugin to smartly and efficiently add client-side components to your web site.

Or, more technically: a framework independent partial hydration islands architecture implementation.

Features:

Installation Jump to heading

npm install @11ty/is-land

Add is-land.js to your primary bundle. It can be deferred and/or loaded asynchronously.

When using with web components it must be the first custom element defined (via customElements.define) on the page. Choose your style:

<script type="module" src="/is-land.js"></script>
<script type="module">
import "/island.js";
</script>

Usage Jump to heading

<is-land>This is an island.</is-land>

Add any number of loading conditions to this tag to control how and when the island is initialized. You can mix and match:

<is-land on:visible on:idle>
<!-- your HTML here -->

<is-land on:media="(min-width: 64em)">
<!-- Islands can be nested -->
<!-- Islands inherit all of their parents’ loading conditions -->
</is-land>
</is-land>

Controlling Fallback Content Jump to heading

Pre-JS Jump to heading

<is-land on:visible on:idle>
<vanilla-web-component>
Put your pre-JS fallback content in your web component.
</vanilla-web-component>
</is-land>

Post-JS with <template> Jump to heading

Place any post-JS content inside of one or more <template data-island> elements anywhere in the <is-land>. These will be swapped with their template content. You can nest an <is-land> in there if you want!

<is-land on:visible on:idle>
<template data-island>
<vanilla-web-component>
This component is post-JS.
</vanilla-web-component>
</template>
</is-land>

Styling Jump to heading

The ready attribute is added to the <is-land> when the island has been hydrated.

<style>
is-land[ready] {
background-color: lightgreen;
}
</style>

Run your own custom JavaScript Jump to heading

This code runs when the island’s loading conditions have been satisfied! Note the type="module/island".

<is-land on:visible>
<script type="module/island">
console.log("Hydrating!");
</script>
</is-land>

Framework Support Jump to heading

Demos and source in the HTML are available for each framework listed here.

autoinit Jump to heading

Use the autoinit and import attributes together to import a third party library (or component code). autoinit can be one of petite-vue, vue, preact, or svelte. It is recommended to use a self-hosted framework library (future Eleventy integrations will automate this for you).

<is-land on:visible autoinit="petite-vue" import="https://unpkg.com/petite-vue@0.4.1/dist/petite-vue.es.js" v-scope="{ name: 'post-JS' }">
Hello from <span v-html="name">pre-JS</span>
</is-land>

<!-- when import maps support is better, this simplifies with an entry for petite-vue in your import map -->
<is-land on:visible import="petite-vue" v-scope="{ name: 'post-JS' }">
Hello from <span v-html="name">pre-JS</span>
</is-land>

Petite Vue Jump to heading

<is-land on:visible autoinit="petite-vue" import="https://unpkg.com/petite-vue@0.4.1/dist/petite-vue.es.js" v-scope="{ name: 'post-JS' }">
Hello from <span v-html="name">pre-JS</span>
</is-land>

Vue Jump to heading

<is-land on:visible>
<div id="vue-app">
Hello from <span v-html="name">pre-JS</span>
</div>

<script type="module/island">
import { createApp } from "https://unpkg.com/vue@3.2.36/dist/vue.esm-browser.prod.js";

createApp({
data: () => ({ name: "post-JS" })
}).mount("#vue-app")
</script>
</is-land>

Svelte Jump to heading

This example uses an Eleventy/Svelte integration to compile a Svelte component.

{% assign component = "./lib/svelte/my-component.svelte" | svelte %}
<is-land on:visible autoinit="svelte" import="{{ component.clientJsUrl }}"></is-land>
Example component code ./lib/svelte/my-component.svelte:
<script>
// using export to allow overrides via props
export let name = 'world';

let count = 0;

function handleClick() {
count += 1;
}
</script>

<style>
h1 { color: red }
</style>

<h1>Hello {name}</h1>

<button on:click={handleClick}>
Clicked {count} {count === 1 ? 'time' : 'times'}
</button>

Preact Jump to heading

This example uses htm instead of JSX.

<is-land on:visible autoinit="preact" import="/lib/preact/preact-component.js"></is-land>
Example component code ./lib/preact/preact-component.js:
import { html, render } from 'https://unpkg.com/htm/preact/index.mjs?module'

function App (props) {
return html`<p><strong>Hello ${props.name}!</strong></p>`;
}

export default function(el) {
render(html`<${App} name="from Preact" />`, el);
}

Lit Jump to heading

<is-land on:visible import="./lib/lit/lit-component.js">
<lit-component name="Post-JS">Pre-JS Content</lit-web-component>
</is-land>
Example component code ./lib/lit/lit-component.js:
import {html, css, LitElement} from "https://cdn.jsdelivr.net/gh/lit/dist@2/core/lit-core.min.js";

customElements.define('lit-component', class extends LitElement {
static properties = {
name: {type: String},
};

render() {
return html`<p>Hello, ${this.name || "Stranger"}!</p>`;
}
});

Alpine.js Jump to heading

<is-land on:visible import="https://unpkg.com/alpinejs">
<div x-data="{ count: 0 }">
Hello from Alpine.js!

<button @click="count++">⬆️</button> <button @click="count--">⬇️</button> <span x-text="count"></span>
</div>
</is-land>

Other pages in Plugins: