Astro shows “Missing hint on client:only directive” when you write client:only without a value. Unlike other directives, client:only skips server rendering, so Astro never runs the component on the server to discover which framework it belongs to. You have to name it: client:only="react", "preact", "vue", "svelte" or "solid-js". The error message suggests the likely value.
Key Takeaways
client:onlyalways needs a framework name as its value.- The value is the renderer name:
react,preact,vue,svelteorsolid-js.- Prefer
client:loadorclient:visibleunless the component truly can’t render on the server.- Components with
client:onlyproduce no HTML until JavaScript runs, so give them space or a fallback.
The fix
---
import Map from '../components/Map.tsx';
---
<!-- Wrong -->
<Map client:only />
<!-- Right -->
<Map client:only="react" />
Valid values match the official integrations:
| Framework | Value |
|---|---|
| React | client:only="react" |
| Preact | client:only="preact" |
| Vue | client:only="vue" |
| Svelte | client:only="svelte" |
| Solid | client:only="solid-js" |
Should you use client:only at all?
client:only exists for components that break during server rendering, typically because they touch window, document or localStorage while rendering, or wrap a browser-only library such as a map or charting tool.
It has costs:
- No HTML in the initial page. Search engines and users without JavaScript see nothing in its place.
- Layout shift. The component appears after the script runs, pushing content down unless you reserve space.
- Slower perceived load. The user waits for the download before seeing anything.
Often you can keep server rendering and move the browser-only code into an effect:
// src/components/Map.tsx
import { useEffect, useRef } from 'react';
export default function Map() {
const ref = useRef<HTMLDivElement>(null);
useEffect(() => {
// browser-only library loads here, after hydration
import('some-map-library').then(({ createMap }) => createMap(ref.current!));
}, []);
return <div ref={ref} style={{ aspectRatio: '16 / 9' }} />;
}
Then <Map client:visible /> renders a sized placeholder on the server and loads the map when it scrolls into view. Lazy-loading islands covers client:visible timing.
Showing something before it loads
Pass a fallback through the fallback slot, which Astro renders in place until the component mounts:
<Map client:only="react">
<div slot="fallback" class="map-placeholder">Loading map…</div>
</Map>
Related
If the integration isn’t installed at all, you’ll see No matching renderer found instead. Every directive is compared in the Astro components guide, and the directives reference has the full rules.
FAQ
Why does client:only need a value when client:load doesn’t?
Other directives render the component on the server first, which tells Astro which renderer to use. client:only skips that step, so Astro needs the hint.
Is client:only bad for SEO?
Its content isn’t in the server HTML, so crawlers that don’t run JavaScript won’t see it. Keep important content out of client:only components.