Skip to content

useMediaQuery

Edit

Subscribes to a CSS media query with a hydration-safe fallback.

useMediaQuery.ts
import { useCallback, useMemo, useSyncExternalStore } from "react";
export interface UseMediaQueryOptions {
defaultValue?: boolean;
}
/** Subscribes to a CSS media query with a hydration-safe server fallback. */
export const useMediaQuery = (
query: string,
options: UseMediaQueryOptions = {},
): boolean => {
const { defaultValue = false } = options;
const list = useMemo(
() =>
typeof window === "undefined" ||
typeof window.matchMedia !== "function"
? null
: window.matchMedia(query),
[query],
);
const subscribe = useCallback(
(notify: () => void) => {
if (list === null) return () => {};
list.addEventListener("change", notify);
return () => list.removeEventListener("change", notify);
},
[list],
);
const getSnapshot = useCallback(() => list?.matches ?? defaultValue, [
defaultValue,
list,
]);
const getServerSnapshot = useCallback(() => defaultValue, [defaultValue]);
return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
};
Terminal
wget -O src/hooks/useMediaQuery.ts https://raw.githubusercontent.com/jrTilak/lazykit/HEAD/registry/react-hooks/useMediaQuery.ts
useMediaQuery.example.tsx
import { useMediaQuery } from "./useMediaQuery";
export const MediaQueryExample = () => {
const isWide = useMediaQuery("(min-width: 48rem)");
return <p>{isWide ? "Wide layout" : "Compact layout"}</p>;
};
  • query (string) — CSS media query passed to matchMedia.
  • options.defaultValue (boolean) — Used during SSR or without matchMedia.

Whether the media query currently matches.