useMediaQuery
React hook that tracks the state of a media query using the Match Media API for responsive design and user preferences.
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
Parameter | Type | Description |
---|---|---|
query | string | The media query string to track |
options | UseMediaQueryOptions | Optional configuration for the hook |
UseMediaQueryOptions
Property | Type | Default | Description |
---|---|---|---|
defaultValue | boolean | false | Default value returned on server or before initialization |
initializeWithValue | boolean | true | Whether 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>
)
Print Styles
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
Query | Description |
---|---|
(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 |
print | Print 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