---
title: 'Lazy hydration with mochi:hydrate:visible'
slug: lazy-hydration
description: 'Defer island hydration until the component scrolls into view with mochi:hydrate:visible.'
---
## Lazy hydration with `mochi:hydrate:visible`
Defer hydration until a component scrolls into the viewport. The component still renders server-side on every request, but its JavaScript and CSS are fetched only when the wrapper intersects the viewport via `IntersectionObserver`.
```svelte
```
Pass an options object to start loading before the element enters the viewport. `rootMargin` is forwarded straight to `IntersectionObserver`:
```svelte
```
The default `rootMargin` is `'0px'` — hydration fires the moment the island's first child crosses the viewport edge. Once intersection fires the observer disconnects, the component bundle imports, the deferred CSS link is appended to `
`, and Svelte hydrates the existing SSR markup.
Do **NOT** assume the island is fully styled before hydration; instead, accept that lazy islands flash unstyled until their CSS link loads. Bundle critical above-the-fold styles into the page shell or use `mochi:hydrate` for anything that must look right pre-hydration.
Do **NOT** nest `mochi:hydrate:visible` inside another hydratable island; instead, hoist it to the page level — nested hydration directives are rejected at compile time.
### Combining with `mochi:defer`
Stack `mochi:defer mochi:hydrate:visible` to defer both rendering and hydration: the placeholder ships with the page, the SSR HTML streams in when the deferred fetch resolves, and the JavaScript loads only after the now-rendered island scrolls into view.
```svelte
```
See `Selective hydration` for the eager `mochi:hydrate` directive and `Server islands` for `mochi:defer` on its own.