Hydrate Only What You Need: Using Astro’s Islands for Targeted Client‑Side Interactivity
Astro’s islands let you hydrate only the interactive parts of a page, keeping the rest static. This blog walks through the core concept, shows how to enable an island, explains the build‑time process, and covers trade‑offs and best practices.
25 Jul 2026, 23:39 UTC

Why Do I Need Islands?
When building a landing page or a blog, you often want a few interactive widgets—like a live counter or a modal—without paying the price of a full single‑page application. Astro’s islands architecture lets you keep the bulk of the page static, loading JavaScript only for the components that actually need it. The result is a faster initial load, smaller bundle, and a simpler development model.
Core Idea: Static Markup + Selective Hydration
Astro renders every component to static HTML on the server. When the page reaches the browser, only the components marked with a client: directive are hydrated. The rest stay as plain HTML, so the browser doesn’t have to run any JavaScript for them.
Hydration triggers can be:
client:only– hydrate immediately after the component mounts.client:idle– hydrate after the browser is idle.client:visible– hydrate when the component enters the viewport.
Enabling an Island: A Step‑by‑Step Example
Below is a minimal Astro project that demonstrates a counter component hydrating only when it becomes visible.
-
Create a new Astro project (if you don’t already have one):
npx create astro@latest my-islands-demo cd my-islands-demo npm install -
Add a counter component in
src/components/Counter.astro:--- import { useState } from 'react'; ---Count: {count}
setCount(c => c + 1)}>IncrementNote: The component uses React for simplicity; you could also use Svelte, Solid, or vanilla JS.
-
Import the component in a page and declare it as an island:
--- import Counter from '../components/Counter.astro?client:visible'; --- <main> Welcome to the Astro Islands DemoBelow is a counter that only hydrates when you scroll it into view.
<Counter /> </main>The
?client:visiblequery string tells Astro to bundle the Counter’s JavaScript and to load it only when the component is visible. -
Run the dev server and inspect:
npm run devOpen
http://localhost:3000in a browser. The page loads quickly and the counter’s markup is already present in the HTML, but you won’t see anyCounter.astrobundle loaded until you scroll the counter into view. -
Verify hydration in DevTools:
// In the Network tab, you should see a script like Counter.astro.astro.js // In the Console, you can type: const counter = document.querySelector('button'); console.log(counter); // Should log the button element only after hydrationOnce the script runs, the button becomes functional and the counter increments.
What Happens Under the Hood?
When Astro builds the project, it creates a lightweight runtime that keeps a map of island boundaries. Each island’s script is bundled separately. The runtime injects a small astro-hydrate.js script that listens for the specified hydration trigger and then dynamically imports the component’s bundle. Because the rest of the page is static, the browser can render it immediately without waiting for any JavaScript.
Trade‑Offs and Limitations
- Component isolation: Islands must be self‑contained. They can’t rely on global state unless you explicitly pass it or use Astro’s
provide/injectsystem. - Styling challenges: CSS that targets the island’s DOM must be included globally or scoped inside the component. Otherwise, styles may not apply until hydration occurs.
- SEO considerations: Content inside islands is still present in the static markup, so search engines can index it. However, if the island contains data that changes after hydration, you need to ensure that the static version is still meaningful.
- Debugging complexity: Because the component’s JavaScript is loaded lazily, breakpoints may not hit until hydration. Use
debuggerstatements or DevTools’ “Pause on script load” feature to catch early.
When to Use Islands
- Small interactive widgets that don’t need a full SPA (e.g., a form, a countdown timer, a modal).
- Pages with heavy static content but a few dynamic parts.
- Sites where performance and first‑content‑ful paint (FCP) are critical.
Actionable Takeaway
Start by identifying the “hot spots” on your page—those few elements that require JavaScript. Wrap them in Astro components, import them with a ?client:… directive, and test the hydration trigger that best fits the user experience (e.g., client:visible for lazy loading, client:idle for background work). Measure the impact with Lighthouse or WebPageTest to confirm the performance win.
Remember: the goal is to keep the majority of your page static while still offering interactivity where it matters. Astro’s islands give you a declarative, fine‑grained way to achieve that balance.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.