Client Directives
client:load, client:idle, and client:visible — controlling when and whether an island hydrates.
2 phút đọc
Importing a React, Vue, or Svelte component into an .astro file renders it to static HTML at build time, the same as any other content — by itself, that component ships zero JavaScript and has no interactivity in the browser. A client directive is what tells Astro "hydrate this one, and here's when."
No directive, no JavaScript
---
import Counter from "../components/Counter.jsx";
---
<Counter />This renders Counter's output as static markup — a button that visually exists but doesn't respond to clicks, because no JavaScript for it was ever sent to the browser. This is intentional and often exactly what you want for a component that only needed a UI framework's templating convenience, not its runtime.
client:load — hydrate immediately
<Counter client:load />The component's JavaScript downloads and hydrates as soon as the page loads, competing with everything else for the browser's attention during initial page load. Reserve this for components that need to be interactive right away and are visible without scrolling — a site-wide nav toggle, a critical form.
client:idle — hydrate when the browser is free
<Newsletter client:idle />Hydration is deferred until the browser reports it's idle (via requestIdleCallback), after more urgent work — like rendering the initial page — has finished. This is a good default for anything interactive but not urgent: the component becomes interactive slightly later, but initial page load isn't competing with its JavaScript.
client:visible — hydrate on scroll into view
<CommentSection client:visible />The component's JavaScript doesn't even download until it scrolls into the viewport, using an IntersectionObserver under the hood. This is ideal for anything below the fold — a comment section, a related-posts widget, a footer newsletter form — since visitors who never scroll that far never pay for that JavaScript at all.
Other directives worth knowing
client:media={query}— hydrates only when a CSS media query matches, useful for a component that's only interactive on mobile (a hamburger menu) or only on desktop.client:only="react"— skips server-side rendering entirely and renders only in the browser; needed for components that depend on browser-only APIs and would error if Astro tried to render them on the server. The framework name is required, since Astro needs to know which renderer to load without inspecting the (skipped) server render.
Choosing a directive
The decision comes down to two questions: does this need to be interactive at all, and if so, how urgently. Above-the-fold and critical to first interaction → client:load. Useful but not urgent → client:idle. Below the fold or easy to miss → client:visible. And if a component is purely presentational — it only ever renders static markup — the right choice is usually no directive at all, letting it ship as HTML with no JavaScript cost whatsoever. Every directive you don't add is bytes a visitor never has to download.