Interactive Components in a Sea of Static HTML
Islands — Intro
Astro renders everything as static HTML by default. An "island" is a component you opt into hydrating — and only that component ships JavaScript.
What you'll learn
- Recognize what an island is
- See the cost difference vs an SPA
- Know when to make something an island
Astro’s superpower: static by default, JavaScript by exception.
Every component renders to HTML on the server. If a component
needs to be interactive in the browser, you mark it with a
client:* directive, and ONLY that component ships JavaScript.
Each interactive component is an island.
What That Looks Like
---
import Header from "../components/Header.astro"; // pure HTML, no JS
import Counter from "../components/Counter.tsx"; // React component
---
<Header />
<main>
<h1>Welcome</h1>
<Counter client:load /> {/* this is an island */}
</main> The output:
Headerand<h1>are HTML — no JS to loadCounterships its React component code + just enough hydration shim to make it interactive
If you removed client:load, the Counter would still render — as
plain HTML, with no behavior. The directive is what asks for
hydration.
The Trade-Off vs SPA
| Mental model | What ships |
|---|---|
| Astro static page | HTML only |
| Astro page with 1 island | HTML + that one component’s code + 1 framework runtime |
| Astro page with N islands | HTML + N components’ code + 1 shared runtime |
| Single-Page App | HTML shell + the whole app + framework + router |
For content-driven sites with a few interactive widgets (a search box, a theme toggle, a comment count), Astro ships dramatically less JS than an SPA.
When To Make Something An Island
- The user needs to click, type, or otherwise interact with it
- It changes after page load (timers, fetches)
- It uses browser APIs (localStorage, mediaQuery)
When NOT to:
- Static content (text, layout, links) — leave it as HTML
- Already pre-rendered data with no interaction — HTML again
- Just because you “might want it later” — wait until you need it
How An Island Hydrates
Astro generates the island’s HTML on the server. The browser downloads a tiny “preload” snippet that, when the directive condition fires (load / idle / visible / etc.), fetches the component’s code and “hydrates” it — turning the static HTML into an interactive DOM.
The next few lessons cover the directives.
Up Next
client:load — the simplest directive.