- Hooks
- Browser hooks
- useMediaQuery
useMediaQuery
Subscribe and respond to media query changes with useMediaQuery.
use-media-query.tsx
"use client";
import React from "react";
import { LaptopIcon, MonitorIcon, PhoneIcon, TabletIcon } from "lucide-react";
import { ClientOnly } from "@/lib/components/utils/client-only";
import { useMediaQuery } from "@/lib/hooks/use-media-query";
import { cn } from "@/lib/utils/classes";
function Demo() {
const isSmallDevice = useMediaQuery("only screen and (max-width : 768px)");
const isMediumDevice = useMediaQuery(
"only screen and (min-width : 769px) and (max-width : 992px)"
);
const isLargeDevice = useMediaQuery(
"only screen and (min-width : 993px) and (max-width : 1200px)"
);
const isExtraLargeDevice = useMediaQuery("only screen and (min-width : 1201px)");
return (
<ClientOnly>
<div className="text-center">
<p>Resize your browser window to see changes.</p>
<div className="mt-8 grid grid-cols-4 gap-4">
{[
{
name: "Small",
isMatched: isSmallDevice,
icon: <PhoneIcon size={20} />,
},
{
name: "Medium",
isMatched: isMediumDevice,
icon: <TabletIcon size={20} />,
},
{
name: "Large",
isMatched: isLargeDevice,
icon: <LaptopIcon size={20} />,
},
{
name: "Extra Large",
isMatched: isExtraLargeDevice,
icon: <MonitorIcon size={20} />,
},
].map(({ name, icon, isMatched }) => (
<div
key={name}
className={cn(
"flex flex-col items-center gap-2 rounded border-2 p-4",
isMatched && "border-green-800 text-green-200"
)}
>
{icon}
<p>{name}</p>
</div>
))}
</div>
</div>
</ClientOnly>
);
}
function ClientOnlyDemo() {
return (
<ClientOnly>
<Demo />
</ClientOnly>
);
}
Installation
Copy and paste the following code into your project.
use-media-query.ts
import * as React from "react";
export function useMediaQuery(query: string) {
const [value, setValue] = React.useState(false);
React.useEffect(() => {
function onChange(event: MediaQueryListEvent) {
setValue(event.matches);
}
const result = matchMedia(query);
result.addEventListener("change", onChange);
setValue(result.matches);
return () => result.removeEventListener("change", onChange);
}, [query]);
return value;
}
// import React from "react";
// export function useMediaQuery(query: string): boolean {
// const subscribe = React.useCallback(
// (callback: (ev: MediaQueryListEvent) => void) => {
// const matchMedia = window.matchMedia(query);
// matchMedia.addEventListener("change", callback);
// return () => {
// matchMedia.removeEventListener("change", callback);
// };
// },
// [query]
// );
// const getSnapshot = () => {
// return window.matchMedia(query).matches;
// };
// const getServerSnapshot = () => {
// throw Error("useMediaQuery is a client-only hook");
// };
// return React.useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
// }
Update the import paths to match your project setup.
PARAMETERS
Name | Type | Description |
---|---|---|
query | string | The media query to listen changes |
Return value
Type | Description |
---|---|
boolean | Returns a boolean value indicating whether the media query matches the current state of the device. |