Join our Discord Community

useMediaQuery

React hook that tracks the state of a media query using the Match Media API for responsive design and user preferences.

Loading component...

Installation

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

Features

  • Responsive design - Track screen size changes and breakpoints
  • User preferences - Detect dark mode, reduced motion, and other preferences
  • Real-time updates - Automatically updates when media query state changes
  • SSR compatible - Optional initialization for server-side rendering
  • Safari support - Uses deprecated listeners for Safari < 14 compatibility
  • Type safety - Full TypeScript support with proper return types

Usage

import { useMediaQuery } from "@/hooks/use-media-query"

function ResponsiveComponent() {
  const isMobile = useMediaQuery("(max-width: 768px)")
  const isDarkMode = useMediaQuery("(prefers-color-scheme: dark)")

  return (
    <div>
      <p>Screen: {isMobile ? "Mobile" : "Desktop"}</p>
      <p>Theme: {isDarkMode ? "Dark" : "Light"}</p>
    </div>
  )
}

API Reference

useMediaQuery

ParameterTypeDescription
querystringThe media query string to track
optionsUseMediaQueryOptionsOptional configuration for the hook

UseMediaQueryOptions

PropertyTypeDefaultDescription
defaultValuebooleanfalseDefault value returned on server or before initialization
initializeWithValuebooleantrueWhether to initialize with actual media query state (set to false for SSR)

Return Value

Returns a boolean indicating whether the media query currently matches.

Usage Examples

Responsive Breakpoints

const isMobile = useMediaQuery("(max-width: 640px)")
const isTablet = useMediaQuery("(min-width: 641px) and (max-width: 1024px)")
const isDesktop = useMediaQuery("(min-width: 1025px)")

return (
  <div>
    {isMobile && <MobileNav />}
    {isTablet && <TabletNav />}
    {isDesktop && <DesktopNav />}
  </div>
)

User Preferences

const prefersDark = useMediaQuery("(prefers-color-scheme: dark)")
const prefersReducedMotion = useMediaQuery("(prefers-reduced-motion: reduce)")
const prefersHighContrast = useMediaQuery("(prefers-contrast: high)")

const animationClass = prefersReducedMotion ? "no-animation" : "animate-bounce"

Device Orientation

const isPortrait = useMediaQuery("(orientation: portrait)")
const isLandscape = useMediaQuery("(orientation: landscape)")

return (
  <div className={isPortrait ? "portrait-layout" : "landscape-layout"}>
    Content adapts to orientation
  </div>
)
const isPrint = useMediaQuery("print")

return (
  <div>
    {!isPrint && <NavigationBar />}
    <Content />
    {!isPrint && <Footer />}
  </div>
)

SSR Compatible

const isMobile = useMediaQuery("(max-width: 768px)", {
  initializeWithValue: false,
  defaultValue: false
})

// Prevents hydration mismatch in SSR applications

Custom Breakpoints

const isXLarge = useMediaQuery("(min-width: 1280px)")
const is4K = useMediaQuery("(min-width: 3840px)")
const isRetina = useMediaQuery("(min-resolution: 2dppx)")

Common Media Queries

QueryDescription
(max-width: 640px)Small screens (mobile)
(min-width: 768px)Medium screens and up (tablet+)
(min-width: 1024px)Large screens and up (desktop+)
(prefers-color-scheme: dark)User prefers dark mode
(prefers-reduced-motion: reduce)User prefers reduced motion
(orientation: portrait)Portrait orientation
(orientation: landscape)Landscape orientation
(hover: hover)Device supports hover interactions
printPrint media type

Implementation Details

  • Uses the native window.matchMedia() API
  • Listens for change events to update state automatically
  • Falls back to deprecated addListener/removeListener for Safari < 14
  • Handles server-side rendering with configurable default values
  • Cleans up event listeners on unmount or query change
  • Supports all CSS media query features and syntax