Client Directives
In a React app every component hydrates as soon as the bundle loads. Astro gives you fine-grained control: each island declares when it should hydrate via a client:* directive. Without any directive, the component renders to static HTML and ships zero JavaScript.
The five directives
Section titled “The five directives”client:load
Section titled “client:load”Hydrates immediately when the page loads. Use this for components that must be interactive right away — a navigation menu, a login form, an above-the-fold widget.
<SearchBar client:load />This is the direct equivalent of a React component in a Next.js page — it hydrates on load. Use it sparingly; every client:load island adds to the initial JS budget.
client:idle
Section titled “client:idle”Hydrates after the browser fires requestIdleCallback — when the main thread is quiet. Use this for interactive components that are important but not immediately critical.
<NewsletterSignup client:idle />In a React app there is no equivalent — everything loads eagerly. client:idle is a free performance win for secondary widgets.
client:visible
Section titled “client:visible”Hydrates once the component’s root element enters the viewport (uses IntersectionObserver). Perfect for below-the-fold islands: comments sections, carousels, interactive charts.
<CommentThread client:visible /><PricingTable client:visible />A user who never scrolls down never downloads the JS. This is the most impactful directive for long pages.
client:media
Section titled “client:media”Hydrates when a CSS media query matches. Use this for islands that only exist in certain layouts — a mobile bottom nav, a desktop sidebar filter.
<MobileMenu client:media="(max-width: 768px)" /><DesktopFilter client:media="(min-width: 1024px)" />Desktop users never download the mobile component’s JS; mobile users never download the desktop one.
client:only
Section titled “client:only”Skips server-side rendering entirely and renders only in the browser. You must pass the framework name as its value. Use this for components that call browser-only APIs (window, localStorage, WebGL) that would crash during SSR.
<ThreeScene client:only="react" /><MapWidget client:only="react" />Without
client:only, Astro still runs your React component on the server to generate the initial HTML. If the component callswindowordocumentat the top level, the SSR step will throw.client:onlyskips that step.
All five directives side by side
Section titled “All five directives side by side”// React/Next.js — no directive system.// All components hydrate on load.// Lazy loading is manual (React.lazy + Suspense).import dynamic from 'next/dynamic';
const HeavyChart = dynamic(() => import('./HeavyChart'), { ssr: false, // skip SSR — closest to client:only});
export default function Page() { return ( <> <SearchBar /> {/* eager hydration */} <HeavyChart /> {/* ssr:false ~ client:only */} {/* No built-in idle/visible/media support */} </> );}---import SearchBar from '../components/SearchBar.jsx';import NewsletterSignup from '../components/NewsletterSignup.jsx';import CommentThread from '../components/CommentThread.jsx';import MobileMenu from '../components/MobileMenu.jsx';import ThreeScene from '../components/ThreeScene.jsx';---<!-- Hydrate immediately --><SearchBar client:load />
<!-- Hydrate when browser is idle --><NewsletterSignup client:idle />
<!-- Hydrate when scrolled into view --><CommentThread client:visible />
<!-- Hydrate only on mobile --><MobileMenu client:media="(max-width: 768px)" />
<!-- Browser-only, skip SSR --><ThreeScene client:only="react" />No directive = static HTML
Section titled “No directive = static HTML”The most important thing to remember: a React component without a directive is static HTML. Astro runs it on the server, renders its output to HTML, and ships nothing to the browser.
---import ProductCard from '../components/ProductCard.jsx';---<!-- No client: directive → static HTML, zero JS --><ProductCard title="Widget" price={29} />This is intentional. Astro encourages you to ask: “does this component actually need to be interactive?” If a React component just renders data, it can be static.