Hydration strategies
When the JavaScript arrives is the whole point of an island. These are real regions on this page. Each block ships static HTML first; the JS toggle shows exactly what the server sent before hydration took over.
hydrate: 'load'
Hydrates as soon as the region's custom element connects, after DOM ready. Use it for the controls a page cannot function without. The JS-off side is the shipped HTML — present, styled, but inert.
import Panel from '$lib/Panel.svelte' with {
hydrate: 'load'
};
<Panel />Live since —
Static HTML
hydrate: 'idle'
Waits for requestIdleCallback (with a timeout fallback). The HTML is
already there; only the listeners and reactive runtime wait for a quiet moment.
import Widget from '$lib/Widget.svelte' with {
hydrate: 'idle'
};
<Widget />Idle after …
--:--:--
Waiting for idle
--:--:--
hydrate: 'visible'
Gated on IntersectionObserver. Below-the-fold content stays SSR HTML until
it approaches the viewport. A visible.margin pre-warms it slightly early.
import Chart from '$lib/Chart.svelte' with {
hydrate: 'visible'
};
<Chart />In view · —
Below the fold
hydrate: '(max-width: 600px)'
Any media query is a strategy, resolved with matchMedia. On a wide window
this stays static until you narrow it — that is the strategy working, not a broken
preview. Mobile-only JS never loads on desktop.
import Drawer from '$lib/Drawer.svelte' with {
hydrate: '(max-width: 600px)'
};
<Drawer />0px · no match
Waiting on viewport
preset: 'demo'
Option tuning cannot go on the import. It lives in plugin config, optionally behind a
named preset. This block uses the demo preset from this site's vite config
(hydrate: 'visible' with a 200px margin).
// vite.config.ts
ogygia({
presets: {
demo: { hydrate: 'visible', margin: '200px' }
}
});
// component
import Panel from '$lib/Panel.svelte' with {
preset: 'demo'
};In view · —
Below the fold