Astro Client-Side Component Directives: load, visible, media, idle, and only Compared
Astro's client: directives control precisely when framework components hydrate on the browser, ranging from immediate page-load execution to conditional triggers based on viewport visibility, CSS media queries, browser idle time, or skipping server-side rendering entirely.
Astro's island architecture ships zero JavaScript by default, requiring you to explicitly opt-in to client-side interactivity using hydration directives. In the withastro/astro source code, these strategies are defined in packages/astro/src/types/public/elements.ts and implemented through the server-side directive extraction logic in packages/astro/src/runtime/server/hydration.ts.
client:load: Immediate Page-Load Hydration
client:load hydrates the component immediately after the page's JavaScript bundle executes.
The directive is defined in packages/astro/src/types/public/elements.ts as part of the AstroClientDirectives interface. During SSR, the extractDirectives function in packages/astro/src/runtime/server/hydration.ts records the directive name (load) and its value (always true). The client build generates an entry point that calls the renderer's hydrate function instantly upon bundle load, ensuring the component is interactive as soon as possible.
Use this for critical UI requiring immediate interactivity, such as navigation menus or carousels that must animate right away.
<Counter client:load />
client:visible: Viewport-Triggered Hydration
client:visible uses an IntersectionObserver to import and hydrate the component only when it enters the browser viewport.
The directive accepts an optional configuration object via the ClientVisibleOptions type, allowing you to specify a rootMargin. During SSR, extractDirectives stores the directive name (visible) and any provided options. The renderer emits client code that registers the IntersectionObserver and lazily loads the component when the element becomes visible.
This is ideal for below-the-fold content like "related posts" widgets or heavy charts that aren't needed until the user scrolls to them. It reduces initial bundle size and improves First Contentful Paint.
<HeavyChart client:visible="{ rootMargin: '200px' }" />
client:media: Media Query-Conditional Hydration
client:media hydrates the component only when the specified CSS media query evaluates to true in the browser, using matchMedia.
Defined as 'client:media'?: string in AstroClientDirectives, this directive requires a string argument containing the media query. In extractDirectives, Astro validates that the value is a string; otherwise it throws the MissingMediaQueryDirective error defined in packages/astro/src/core/errors/errors-data.ts. The generated client code registers a listener to conditionally import the component when the query matches.
Use this for responsive UI patterns like sidebars that should only load on desktop screens, or for respecting prefers-reduced-motion without shipping unnecessary code to all users.
<Sidebar client:media="(min-width: 1024px)" />
client:idle: Idle-Time Hydration
client:idle defers hydration until the browser's main thread is idle using requestIdleCallback (with a polyfill fallback).
Declared as 'client:idle'?: IdleRequestOptions | boolean in packages/astro/src/types/public/elements.ts, this directive accepts either a boolean or an options object to customize the timeout. The extractDirectives function captures these options, and the renderer wraps the component import in a requestIdleCallback call, respecting any user-provided timeout settings.
Use this for non-essential UI that can wait until critical work completes, such as newsletter signup forms or chat widgets. This keeps the critical path short and improves perceived performance.
<NewsletterForm client:idle="{ timeout: 2000 }" />
client:only: Client-Exclusive Rendering
client:only skips server-side rendering entirely, emitting only a placeholder comment (<!--client-only-->) and hydrating exclusively on the client.
Because Astro cannot infer the correct renderer without SSR, this directive requires a framework hint string (e.g., "react", "vue", "svelte"). Defined as 'client:only'?: boolean | string in packages/astro/src/types/public/elements.ts, the directive triggers the NoClientEntrypoint error from packages/astro/src/core/errors/errors-data.ts if the hint is missing. During SSR, extractDirectives records the directive but does not attempt to render the component.
Use this for components relying on browser-only APIs like window, document, or WebGL that would error during SSR, or when minimizing server bundle size is prioritized over immediate interactivity.
<Map client:only="leaflet" />
How Astro Processes Hydration Directives Internally
The hydration strategy follows a consistent pipeline across all directives:
- Parsing: The compiler identifies props starting with
client:and captures them viaextractDirectivesinpackages/astro/src/runtime/server/hydration.ts. - Validation: Directive names are checked against the supported set from active renderers; invalid names raise hydration errors.
- SSR Handling: For
client:load,visible,media, andidle, Astro renders static markup as a placeholder. Forclient:only, only a placeholder comment is emitted. - Client Build: The renderer generates a client entry point implementing the specific loading strategy (eager import,
IntersectionObserver,matchMedia,requestIdleCallback, or direct import). - Runtime: The browser executes the appropriate strategy based on the recorded directive and its value.
Summary
client:load: Hydrates immediately when the page JavaScript loads. Use for critical interactive UI.client:visible: Hydrates when the component enters the viewport viaIntersectionObserver. Use for scroll-triggered content.client:media: Hydrates only when a CSS media query matches viamatchMedia. Use for responsive, conditional UI.client:idle: Hydrates when the main thread is idle viarequestIdleCallback. Use for non-essential, low-priority components.client:only: Skips SSR entirely and hydrates only on the client with a required framework hint. Use for browser-only APIs.
Frequently Asked Questions
What is the difference between client:load and client:idle?
client:load imports and hydrates the component immediately after the page's JavaScript bundle executes, potentially blocking the main thread. client:idle uses requestIdleCallback to defer hydration until the browser has completed more critical work, making it better for non-essential components that don't require immediate interactivity.
When should I use client:only instead of client:load?
Use client:only when your component depends on browser-only globals like window or document that would cause errors during server-side rendering, or when you want to eliminate the component from the server bundle entirely. Use client:load when you need the component to hydrate immediately but still require its static markup during SSR for SEO or initial paint.
Can I use multiple client directives on the same component?
No, Astro does not support combining multiple client: directives on a single component. Each directive represents a distinct hydration strategy, and you must choose the one that best fits your component's loading requirements. If you need complex conditional logic, handle it inside the component after initial hydration.
How does client:visible improve page performance?
client:visible improves performance by preventing the browser from downloading and executing a component's JavaScript until the user actually scrolls to it. This reduces initial bundle size, improves First Contentful Paint, and conserves bandwidth for below-the-fold content that may never be viewed.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →