useMediaQuery()
Last updated: 24/04/2026
Overview
useMediaQuery subscribes to window.matchMedia(query) (or a targetWindow you pass) and returns a boolean that updates whenever the query’s truth value flips-typical uses are responsive breakpoints, prefers-reduced-motion, color-scheme, or pointer/hover capabilities. On the server or when matchMedia is missing, it falls back to defaultValue, and initializeWithValue lets you skip the synchronous read on first render (useful if you want a stable SSR markup then hydrate to the real match in useEffect). The effect re-binds when query or targetWindow changes so derived layout stays correct across navigation or embedded iframes.
What it accepts
query- Any valid CSS media query string (for example(max-width: 768px)).- Optional
options-defaultValue,initializeWithValue,targetWindow.
What it returns
boolean- Whether the media query currently matches.
Usage
Breakpoint plus explicit options: mobile-first default during SSR, then live matchMedia in the browser window.
import useMediaQuery from '@dedalik/use-react/useMediaQuery'
function Example() {
const isNarrow = useMediaQuery('(max-width: 640px)', {
defaultValue: true,
initializeWithValue: false,
targetWindow: typeof window !== 'undefined' ? window : undefined,
})
return (
<div>
<h3>Layout hint</h3>
<p>
Viewport treats this as <strong>{isNarrow ? 'narrow' : 'wide'}</strong> (<= 640px).
</p>
<nav
style={{
display: 'flex',
flexDirection: isNarrow ? 'column' : 'row',
gap: 8,
}}
>
<a href='#a'>Home</a>
<a href='#b'>Docs</a>
<a href='#c'>Contact</a>
</nav>
</div>
)
}
export default function Demo() {
return <Example />
}API Reference
useMediaQuery
Signature: useMediaQuery(query: string, options?: UseMediaQueryOptions): boolean
Parameters
query(string) - Media query evaluated viamatchMedia.options(UseMediaQueryOptions, optional) - Default:{}.defaultValue(boolean, optional) - Used whentargetWindow/matchMediais unavailable. Defaultfalse.initializeWithValue(boolean, optional) - Iftrue, initial state callsmatchMediasynchronously; iffalse, starts fromdefaultValue. Defaulttrue.targetWindow(Window, optional) - Window whosematchMediato use; defaults to globalwindowin the browser.
Returns
boolean - Current matches for the query.
Copy-paste hook
TypeScript
import { useEffect, useState } from 'react'
export interface UseMediaQueryOptions {
defaultValue?: boolean
initializeWithValue?: boolean
targetWindow?: Window
}
const isBrowser = typeof window !== 'undefined'
export default function useMediaQuery(query: string, options: UseMediaQueryOptions = {}): boolean {
const { defaultValue = false, initializeWithValue = true, targetWindow = isBrowser ? window : undefined } = options
const getMatches = (): boolean => {
if (!targetWindow || typeof targetWindow.matchMedia !== 'function') {
return defaultValue
}
return targetWindow.matchMedia(query).matches
}
const [matches, setMatches] = useState<boolean>(() => (initializeWithValue ? getMatches() : defaultValue))
useEffect(() => {
if (!targetWindow || typeof targetWindow.matchMedia !== 'function') {
return
}
const mediaQueryList = targetWindow.matchMedia(query)
const listener = (event: MediaQueryListEvent) => {
setMatches(event.matches)
}
setMatches(mediaQueryList.matches)
mediaQueryList.addEventListener('change', listener)
return () => {
mediaQueryList.removeEventListener('change', listener)
}
}, [query, targetWindow])
return matches
}
export type UseMediaQueryType = ReturnType<typeof useMediaQuery>JavaScript
import { useEffect, useState } from 'react'
const isBrowser = typeof window !== 'undefined'
export default function useMediaQuery(query, options = {}) {
const { defaultValue = false, initializeWithValue = true, targetWindow = isBrowser ? window : undefined } = options
const getMatches = () => {
if (!targetWindow || typeof targetWindow.matchMedia !== 'function') {
return defaultValue
}
return targetWindow.matchMedia(query).matches
}
const [matches, setMatches] = useState(() => (initializeWithValue ? getMatches() : defaultValue))
useEffect(() => {
if (!targetWindow || typeof targetWindow.matchMedia !== 'function') {
return
}
const mediaQueryList = targetWindow.matchMedia(query)
const listener = (event) => {
setMatches(event.matches)
}
setMatches(mediaQueryList.matches)
mediaQueryList.addEventListener('change', listener)
return () => {
mediaQueryList.removeEventListener('change', listener)
}
}, [query, targetWindow])
return matches
}