Hydration Directives
Hydration directives let you control when an island becomes interactive using standard
data-* attributes. This avoids loading JavaScript until it's actually needed.
Usage
Add data-island and data-hydrate attributes to any standard HTML element:
<!-- Hydrate immediately (default) --> <nav data-island="/js/islands/nav.js" data-hydrate="load"> ... </nav> <!-- Hydrate when browser is idle --> <aside data-island="/js/islands/sidebar.js" data-hydrate="idle"> ... </aside> <!-- Hydrate when scrolled into view --> <div data-island="/js/islands/chart.js" data-hydrate="visible"> <canvas>...</canvas> </div>
Activating
Call hydrateIslands() once in your shell script:
import { hydrateIslands } from 'weblisk/core/hydrate.js'; hydrateIslands();
Strategies
| Strategy | Attribute | When |
|----------|-----------|------|
| load | data-hydrate="load" | Immediately on page load (default) |
| idle | data-hydrate="idle" | When the browser is idle
(requestIdleCallback) |
| visible | data-hydrate="visible" | When the element enters the viewport
(IntersectionObserver) |
| media | data-hydrate="media" + data-media="(max-width:768px)" |
When a media query matches |
| event | data-hydrate="event" + data-event="click" | On the first
occurrence of an event |
| never | data-hydrate="never" | Never hydrate (static only) |
Examples
Mobile-Only Island
<div data-island="/js/islands/mobile-menu.js" data-hydrate="media" data-media="(max-width:768px)"> <button class="hamburger">☰</button> </div>
The JavaScript only loads on mobile viewports.
Click-to-Activate
<div data-island="/js/islands/video-player.js" data-hydrate="event" data-event="click"> <div class="video-placeholder"> <img src="/thumb.jpg" alt="Video thumbnail" /> <span>Click to play</span> </div> </div>
The video player script loads only after the user clicks.
Below-the-Fold Content
<div data-island="/js/islands/comments.js" data-hydrate="visible"> <section class="comments"> <!-- Server-rendered comment HTML --> </section> </div>
Comments hydrate only when the user scrolls down to them.
Declarative Event Binding
Bind events directly in HTML using data-on: attributes. The island module exports an actions object with named methods:
<div data-island="/js/islands/toolbar.js" data-hydrate="load"> <button data-on:click="save">Save</button> <button data-on:click="reset">Reset</button> <input data-on:input="search" /> </div>
// js/islands/toolbar.js export const actions = { save(e) { /* save logic */ }, reset(e) { /* reset logic */ }, search(e) { /* filter on input */ }, };
Works with any DOM event: data-on:submit, data-on:change, data-on:keydown, etc.
How It Works
Each strategy uses a different browser API:
- load —
import()directly - idle —
requestIdleCallback(falls back tosetTimeout) - visible —
IntersectionObserverwith a configurable root margin (data-margin) - media —
matchMedialistener - event —
addEventListenerwith{ once: true } - never — skipped entirely
The island script must export a default function that receives the element:
// js/islands/my-island.js export default function myIsland(el) { // el is the element with [data-island] el.querySelector('button').addEventListener('click', () => { // ... }); }