client:load
Astro ships zero JavaScript by default, so a UI framework component rendered in a .astro file is static HTML unless you explicitly opt it into hydration. The client:load directive is the most eager option: it tells Astro to ship the component’s JavaScript and hydrate the island as soon as the page loads. Use it for interactive elements that the user is likely to reach for immediately, where any delay in interactivity would be noticeable.
How client:load works
When you add client:load to a framework component, Astro renders its initial HTML on the server (so it appears instantly), then includes a small runtime that downloads the component’s JS and “hydrates” the static markup into a live, interactive island. Hydration begins at page load — specifically, the script is fetched and executed as soon as the browser has parsed the page, without waiting for idle time or viewport visibility.
---
// src/pages/index.astro
import Counter from "../components/Counter.jsx";
import Newsletter from "../components/Newsletter.jsx";
---
<html lang="en">
<body>
<h1>Welcome</h1>
<!-- Hydrates immediately on load -->
<Counter client:load />
<!-- Static HTML, never shipped to the client -->
<Newsletter />
</body>
</html>
Here Counter becomes interactive right away, while Newsletter stays as server-rendered HTML with no client JavaScript at all. Each client:* island is independent — hydrating one does not pull in the others.
A typical interactive component looks the same as it would in any framework:
// src/components/Counter.jsx
import { useState } from "react";
export default function Counter() {
const [count, setCount] = useState(0);
return (
<button onClick={() => setCount(count + 1)}>
Count: {count}
</button>
);
}
Tip:
client:loadonly changes when JavaScript runs. The component’s HTML is already on the page from server rendering, so users see content immediately —client:loadjust makes the existing markup interactive as quickly as possible.
When to use it
client:load is the right choice when interactivity is needed without delay and the component is above the fold or central to the page’s purpose. Because it competes for bandwidth and main-thread time during the most critical part of page load, reserve it for components that genuinely warrant priority.
Good candidates include:
- A search box or command palette at the top of the page.
- A primary call-to-action with interactive behavior (e.g., an add-to-cart button).
- A theme toggle or navigation menu that users tap right away.
- Form inputs with immediate client-side validation.
For anything below the fold or secondary, a lazier directive avoids paying the cost upfront.
Comparing client directives
client:load sits at the eager end of the hydration spectrum. The alternatives defer work to reduce the JavaScript that runs during initial load.
| Directive | Hydrates when | Best for |
|---|---|---|
client:load | Immediately at page load | Above-the-fold, must-be-interactive components |
client:idle | Browser is idle (requestIdleCallback) | Lower-priority interactive components |
client:visible | Component scrolls into the viewport | Below-the-fold widgets, carousels |
client:media | A CSS media query matches | Components only needed at certain breakpoints |
client:only | At load, with no SSR HTML | Browser-only components (no server render) |
The key trade-off: client:load maximizes responsiveness at the cost of competing with everything else loading. Deferring with client:idle or client:visible improves metrics like Time to Interactive and Total Blocking Time when a component is not needed instantly.
Warning: Avoid sprinkling
client:loadon every island. Each one adds to the JavaScript executed during initial load, which can erode the performance advantage that Astro’s islands architecture is designed to deliver.
Passing props and using it with any framework
The directive works identically across React, Vue, Svelte, Preact, and Solid integrations. Props are serialized from the server and passed to the hydrated island, so you can seed state on the server and let the client take over.
---
import ColorPicker from "../components/ColorPicker.svelte";
---
<ColorPicker client:load initialColor="#7c3aed" presets={["#ef4444", "#10b981"]} />
Add the relevant integration with the CLI so the framework runtime is available:
npx astro add react
Output:
✔ Resolving packages...
Astro will run the following command:
npm install @astrojs/react react react-dom
✔ Continue? … yes
✔ Installing dependencies...
✔ Adding integration to astro.config.mjs
Success! Added the following integration to your project:
- @astrojs/react
Best practices
- Use
client:loadonly for components that must be interactive the instant the page appears. - Prefer
client:visibleorclient:idlefor anything below the fold or non-essential to lower initial JavaScript cost. - Keep eagerly hydrated components small and focused so their bundles stay light.
- Pass only serializable props; functions and class instances cannot cross the server-to-client boundary.
- Audit your pages periodically — count
client:loadusages and downgrade any that don’t truly need eager hydration. - Remember that omitting a directive entirely keeps a component as zero-JS server-rendered HTML, which is almost always the cheapest option.