dotUI
dotUI
beta
  1. Hooks
  2. Browser hooks
  3. useMediaQuery

useMediaQuery

Subscribe and respond to media query changes with useMediaQuery.

"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.

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

NameTypeDescription
query
string
The media query to listen changes

Return value

TypeDescription
boolean
Returns a boolean value indicating whether the media query matches the current state of the device.

Built by mehdibha. The source code is available on GitHub.