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.jsonpnpm dlx shadcn@latest add https://unlogg.com/r/use-is-client.jsonbunx shadcn@latest add https://unlogg.com/r/use-is-client.jsonNotes
- Returns
falseduring server-side rendering andtrueafter 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