patternjavascriptastroModerate
Astro islands architecture — partial hydration with client directives
Viewed 0 times
Astro 2.0+
astro islandspartial hydrationclient:loadclient:visibleclient:idleclient:onlyzero javascript
Error Messages
Problem
Sending a fully interactive JavaScript bundle for every component when most content is static. Developers hydrate the entire page unnecessarily, destroying Astro's performance advantage.
Solution
Use client: directives to hydrate only interactive components:
---
// Only import interactive components where needed
import StaticHeader from './Header.astro'; // zero JS
import InteractiveCart from './Cart.vue'; // needs hydration
import LazyChart from './Chart.svelte'; // heavy — load late
import AboveFold from './Hero.react'; // visible immediately
---
<!-- Zero JS: Astro component, rendered server-side only -->
<StaticHeader />
<!-- Hydrate immediately on page load -->
<AboveFold client:load />
<!-- Hydrate when visible in viewport (best for below-fold) -->
<LazyChart client:visible />
<!-- Hydrate when browser is idle (non-critical) -->
<InteractiveCart client:idle />
<!-- Hydrate only on matching media query -->
<MobileMenu client:media="(max-width: 768px)" />
<!-- Hydrate only on the client, skip SSR entirely -->
<BrowserOnlyWidget client:only="react" />
---
// Only import interactive components where needed
import StaticHeader from './Header.astro'; // zero JS
import InteractiveCart from './Cart.vue'; // needs hydration
import LazyChart from './Chart.svelte'; // heavy — load late
import AboveFold from './Hero.react'; // visible immediately
---
<!-- Zero JS: Astro component, rendered server-side only -->
<StaticHeader />
<!-- Hydrate immediately on page load -->
<AboveFold client:load />
<!-- Hydrate when visible in viewport (best for below-fold) -->
<LazyChart client:visible />
<!-- Hydrate when browser is idle (non-critical) -->
<InteractiveCart client:idle />
<!-- Hydrate only on matching media query -->
<MobileMenu client:media="(max-width: 768px)" />
<!-- Hydrate only on the client, skip SSR entirely -->
<BrowserOnlyWidget client:only="react" />
Why
Astro's islands architecture treats interactive components as isolated 'islands' of JavaScript in a sea of static HTML. Server-renders everything by default (zero JS), and hydrates only the islands that need it, with precise timing control.
Gotchas
- client:only skips server rendering — the component won't appear in SSG/SSR HTML
- client:visible uses IntersectionObserver — not available in all environments
- Props passed to hydrated components must be serializable (no functions, class instances)
- Islands don't share state by default — use nanostores or a global store for cross-island communication
Code Snippets
Cross-island communication with nanostores
---
// Cross-island state with nanostores
import { cartCount } from '../stores/cart';
---
<CartIcon client:load />
<CartDrawer client:idle />
<!-- Both components import and share the same nanostores store -->Context
When choosing how to hydrate interactive components in an Astro application
Revisions (0)
No revisions yet.