Join our Discord Community

useIsClient

React hook that determines if the code is running on the client side (in the browser) for conditional rendering and SSR compatibility.

Loading component...

Installation

npx shadcn@latest add https://www.shadcn.io/registry/use-is-client.json
npx shadcn@latest add https://www.shadcn.io/registry/use-is-client.json
pnpm dlx shadcn@latest add https://www.shadcn.io/registry/use-is-client.json
bunx shadcn@latest add https://www.shadcn.io/registry/use-is-client.json

Features

  • SSR compatible - Prevents hydration mismatches in server-side rendered apps
  • Simple API - Returns a boolean indicating client vs server execution
  • Hydration safe - Starts as false, becomes true after client hydration
  • Zero dependencies - Lightweight hook using only React primitives
  • Performance optimized - Uses useEffect to detect client-side execution

Usage

import { useIsClient } from "@/hooks/use-is-client"

function MyComponent() {
  const isClient = useIsClient()

  return (
    <div>
      {isClient ? (
        <p>This renders on the client</p>
      ) : (
        <p>This renders on the server</p>
      )}
    </div>
  )
}

API Reference

useIsClient

useIsClient(): boolean

Returns a boolean value indicating whether the code is running on the client side.

  • Returns: boolean
    • false - Code is running on the server or before hydration
    • true - Code is running on the client after hydration

Usage Examples

Conditional Browser API Access

function BrowserAPIComponent() {
  const isClient = useIsClient()

  return (
    <div>
      {isClient ? (
        <p>Window width: {window.innerWidth}px</p>
      ) : (
        <p>Window width: Not available on server</p>
      )}
    </div>
  )
}

Preventing Hydration Mismatches

function RandomComponent() {
  const isClient = useIsClient()
  
  // This prevents hydration mismatches since Math.random() 
  // would produce different values on server vs client
  if (!isClient) {
    return <div>Loading...</div>
  }

  return <div>Random number: {Math.random()}</div>
}

Client-Only Components

function ClientOnlyFeature() {
  const isClient = useIsClient()

  if (!isClient) {
    return <div className="h-32 bg-muted animate-pulse" />
  }

  return (
    <div>
      <p>Current URL: {window.location.href}</p>
      <p>User Agent: {navigator.userAgent}</p>
      <p>Online: {navigator.onLine ? "Yes" : "No"}</p>
    </div>
  )
}

Conditional Script Loading

function AnalyticsWrapper() {
  const isClient = useIsClient()

  useEffect(() => {
    if (isClient) {
      // Safe to load analytics scripts on client
      loadAnalytics()
    }
  }, [isClient])

  return <div>Content with analytics</div>
}

Local Storage Access

function UserPreferences() {
  const isClient = useIsClient()
  const [theme, setTheme] = useState('light')

  useEffect(() => {
    if (isClient) {
      const savedTheme = localStorage.getItem('theme') || 'light'
      setTheme(savedTheme)
    }
  }, [isClient])

  const handleThemeChange = (newTheme: string) => {
    setTheme(newTheme)
    if (isClient) {
      localStorage.setItem('theme', newTheme)
    }
  }

  return (
    <div>
      <p>Current theme: {theme}</p>
      <button onClick={() => handleThemeChange('dark')}>
        Dark Theme
      </button>
    </div>
  )
}

Media Query Fallbacks

function ResponsiveComponent() {
  const isClient = useIsClient()
  const [isMobile, setIsMobile] = useState(false)

  useEffect(() => {
    if (isClient) {
      const checkMobile = () => {
        setIsMobile(window.innerWidth < 768)
      }
      checkMobile()
      window.addEventListener('resize', checkMobile)
      return () => window.removeEventListener('resize', checkMobile)
    }
  }, [isClient])

  if (!isClient) {
    // Render a safe default during SSR
    return <div className="desktop-layout">Content</div>
  }

  return (
    <div className={isMobile ? "mobile-layout" : "desktop-layout"}>
      Content
    </div>
  )
}

Common Use Cases

  • Browser API access - Safely use window, document, navigator objects
  • Preventing hydration mismatches - Avoid server/client render differences
  • Client-only features - Geolocation, clipboard, notifications
  • Local storage operations - Read/write browser storage safely
  • Third-party scripts - Load analytics, ads, or other client-only scripts
  • Media queries - Handle responsive behavior with JavaScript
  • Random values - Generate client-side random content safely
  • Time-sensitive content - Display current time without hydration issues

Implementation Details

  • Starts with isClient: false to match server-side rendering
  • Uses useEffect to set isClient: true after component mounts
  • useEffect only runs on the client, never on the server
  • Prevents hydration mismatches by ensuring consistent initial render
  • Minimal performance impact - only one state update after mount
  • Works with all React frameworks (Next.js, Remix, Gatsby, etc.)

Best Practices

  1. Use for browser APIs: Always wrap browser-specific code with this hook
  2. Provide fallbacks: Show loading states or safe defaults during SSR
  3. Avoid overuse: Only use when necessary to prevent unnecessary client-only rendering
  4. Combine with Suspense: Use with React Suspense for better loading experiences
  5. Cache results: Consider memoizing expensive client-only computations