Browse the docs
HooksNo. 107 of 109
useMediaQuery
Subscribes to a CSS media query. SSR-safe: renders a fallback on the server and hydrates without a mismatch.
Installation
pnpm dlx shadcn@latest add @corsair-ui/use-media-queryNo setup needed: the CLI finds @corsair-ui in the shadcn registry directory. The files land in your project as source: edit them like your own code. More in Installation.
Examples
Live queries
Resize the window or change your OS settings.
- Viewport at least 768px wide
(min-width: 768px) - no match
- Reduced motion requested
(prefers-reduced-motion: reduce) - no match
- Touch-first pointer
(pointer: coarse) - no match
API
| Prop | Type | Default |
|---|---|---|
queryAny CSS media query. | string | — |
defaultValueReturned on the server and during hydration. | boolean | false |
Compatibility
- Tailwind CSS
- 3.4 and 4, both checked in CI
- React
- 19
- Rendering
- Works in server components
Source
1 file, installed as source you own
use-media-query.tsView on GitHubimport { useCallback, useSyncExternalStore } from "react";
export interface UseMediaQueryOptions {
/**
* What to render before the browser can answer: on the server and during
* hydration. Pick the value that matches your most common viewport to avoid
* a visible swap after hydration.
*/
defaultValue?: boolean;
}
/**
* Tracks whether a CSS media query currently matches.
*
* Built on `useSyncExternalStore`, so hydration uses `defaultValue` and then
* re-renders with the real match, instead of starting at `false` and flashing
* the wrong layout the way a `useState` + `useEffect` version does.
*
* @example
* const isDesktop = useMediaQuery("(min-width: 768px)");
* const prefersReducedMotion = useMediaQuery("(prefers-reduced-motion: reduce)");
*/
export function useMediaQuery(query: string, { defaultValue = false }: UseMediaQueryOptions = {}) {
const subscribe = useCallback(
(onChange: () => void) => {
const mediaQueryList = window.matchMedia(query);
mediaQueryList.addEventListener("change", onChange);
return () => mediaQueryList.removeEventListener("change", onChange);
},
[query]
);
const getSnapshot = () => window.matchMedia(query).matches;
const getServerSnapshot = () => defaultValue;
return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
}