Skip to content
Astro as islands 4 min read

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:load only changes when JavaScript runs. The component’s HTML is already on the page from server rendering, so users see content immediately — client:load just 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.

DirectiveHydrates whenBest for
client:loadImmediately at page loadAbove-the-fold, must-be-interactive components
client:idleBrowser is idle (requestIdleCallback)Lower-priority interactive components
client:visibleComponent scrolls into the viewportBelow-the-fold widgets, carousels
client:mediaA CSS media query matchesComponents only needed at certain breakpoints
client:onlyAt load, with no SSR HTMLBrowser-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:load on 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:load only for components that must be interactive the instant the page appears.
  • Prefer client:visible or client:idle for 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:load usages 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.
Last updated June 14, 2026
Was this helpful?