BuildBot

Islands First

Islands & partial hydration

Lesson 3 of 5

What you'll learn

  • Explain why Astro ships no JavaScript by default
  • Opt a component into hydration with a client:* directive
  • Compare client:load, client:idle, and client:visible

By default, Astro renders every component to static HTML and ships no JavaScript at all. A page is a sea of inert HTML with a few interactive islands — and only those islands carry JS. This is the islands architecture: hydrate the parts that need behavior, leave the rest as plain markup.

You opt a component in with a client:* directive. Without one, the component is static no matter what it is.

---
import Counter from "../components/Counter.jsx";
import Newsletter from "../components/Newsletter.jsx";
---
<Counter client:visible />
<Newsletter client:idle />
<footer>© 2026</footer>

The directive picks when JS loads

Each directive trades startup cost against interactivity-readiness:

<Widget client:load />     <!-- hydrate immediately on page load -->
<Widget client:idle />     <!-- wait until the browser is idle -->
<Widget client:visible />  <!-- wait until it scrolls into view -->

A component with no directive ships zero JS for that island. client:visible is the cheapest interactive option because nothing below the fold loads until the user actually reaches it.

Static by default cuts both ways

Forget the directive and your interactive component renders as dead HTML — no errors, just nothing happens on click. If interactivity is missing, the first thing to check is whether the island has a client:* directive.

Hydration is a filter: given components and their directives, decide which ones ship JS. The challenge models that decision and the bytes saved.

Decide which islands hydrate

Run it. For each component, a client:* directive means it ships JS and hydrates; no directive means static-only. Tally the JS bytes saved by the static ones.

Loading editor…

Next: where the content itself lives.

Sign in to save your progress across devices.