useIsClient
A custom React hook that determines if the code is running on the client side (in the browser).
useIsClient
is a custom React hook that determines whether the code is running on the client side (in the browser) as opposed to the server. This hook is essential for SSR applications to prevent hydration mismatches and safely access browser-only APIs. It returns false
during server-side rendering and true
after the component mounts on the client.
Example
Loading...
Install
npx shadcn@latest add https://unlogg.com/r/use-is-client.json
pnpm dlx shadcn@latest add https://unlogg.com/r/use-is-client.json
bunx shadcn@latest add https://unlogg.com/r/use-is-client.json
Notes
- Returns
false
during server-side rendering andtrue
after client hydration - Prevents hydration mismatches in SSR applications
- Enables safe access to browser-only APIs like
window
,document
,localStorage
- Automatically handles the server/client state transition
- Zero dependencies with minimal performance overhead
API Reference
Parameters
Prop | Type | Default |
---|---|---|
No parameters? | — | — |
Returns
Prop | Type | Default |
---|---|---|
isClient? | boolean | - |
Usage
import { useIsClient } from "@/hooks/use-is-client";
Advanced Usage
Progressive Enhancement
You can use the hook to progressively enhance your components:
function EnhancedComponent() {
const isClient = useIsClient();
return (
<div>
{/* Always rendered (core functionality) */}
<BasicContent />
{/* Progressive enhancement */}
{isClient && (
<>
<InteractiveFeatures />
<ClientOnlyWidgets />
</>
)}
</div>
);
}
Safe Browser API Access
Combine with useEffect
for safe browser API access:
function BrowserInfo() {
const isClient = useIsClient();
const [info, setInfo] = useState(null);
useEffect(() => {
if (isClient) {
// Safe to access browser APIs
setInfo({
userAgent: navigator.userAgent,
language: navigator.language,
onLine: navigator.onLine,
});
}
}, [isClient]);
if (!isClient) return <div>Loading browser info...</div>;
return (
<div>
<p>Browser: {info?.userAgent}</p>
<p>Language: {info?.language}</p>
<p>Online: {info?.onLine ? "Yes" : "No"}</p>
</div>
);
}
Preventing Layout Shift
Use placeholders to prevent layout shift during hydration:
function ResponsiveComponent() {
const isClient = useIsClient();
return (
<div>
{!isClient ? (
// Placeholder with same dimensions
<div className="h-48 bg-gray-200 animate-pulse rounded" />
) : (
<DynamicContent />
)}
</div>
);
}
Local Storage Integration
function UserPreferences() {
const isClient = useIsClient();
const [theme, setTheme] = useState('light');
useEffect(() => {
if (isClient) {
const savedTheme = localStorage.getItem('theme');
if (savedTheme) {
setTheme(savedTheme);
}
}
}, [isClient]);
const updateTheme = (newTheme: string) => {
setTheme(newTheme);
if (isClient) {
localStorage.setItem('theme', newTheme);
}
};
return (
<div className={`theme-${theme}`}>
<button onClick={() => updateTheme(theme === 'light' ? 'dark' : 'light')}>
{isClient ? `Switch to ${theme === 'light' ? 'dark' : 'light'} theme` : 'Loading...'}
</button>
</div>
);
}
Use Cases
- Server-Side Rendering: Prevent hydration mismatches in Next.js, Remix, or other SSR frameworks
- Progressive Enhancement: Add client-only features without breaking server rendering
- Browser API Access: Safely use
window
,document
,localStorage
,sessionStorage
, etc. - Third-Party Widgets: Conditionally render client-only components like maps, charts, or social widgets
- Feature Detection: Enable features only when JavaScript is available
- Performance Optimization: Defer heavy client-side components until after hydration
- Conditional Imports: Load client-only libraries or components dynamically
- Analytics Integration: Initialize tracking scripts only on the client side