How to Handle Media Queries in React Logic with a Custom Hook

Published: (December 10, 2025 at 08:05 PM EST)
3 min read
Source: Dev.to

Source: Dev.to

Introduction

CSS media queries are fantastic for styling—changing font sizes, padding, or grid layouts based on screen width.
But what happens when you need to change the logic or structure of your application?

For example, on desktop you might want a persistent Sidebar on the left, while on mobile that same sidebar needs to be a Sheet or Modal that slides in when a button is clicked. You can’t achieve this with just display: none because the components behave differently. This is where JavaScript media queries come in.

In this post, I’ll share a lightweight custom hook, useMediaQuery, that lets you detect screen sizes directly inside your React components.

The Problem with “CSS‑Only” Hiding

A common mistake is rendering both the mobile and desktop components and hiding one using CSS.

{/* This is bad for performance! */}

This approach bloats the DOM because React still renders both components, runs their effects and logic, even if the user can’t see them.

The Solution: useMediaQuery Hook

By using the native window.matchMedia API inside a React hook, we can track the screen state efficiently.

import { useEffect, useState } from "react";

export function useMediaQuery(query: string): boolean {
  const [matches, setMatches] = useState(false);

  useEffect(() => {
    const media = window.matchMedia(query);

    // Update state immediately if it doesn't match
    if (media.matches !== matches) {
      setMatches(media.matches);
    }

    // Listener for subsequent changes
    const listener = () => setMatches(media.matches);

    // Modern browsers use addEventListener for matchMedia
    media.addEventListener("change", listener);

    // Clean up the listener on unmount
    return () => media.removeEventListener("change", listener);
  }, [matches, query]);

  return matches;
}

How It Works

  • window.matchMedia(query) – Checks if the document matches the media query string (e.g., (max-width: 768px)).
  • useState – Stores the result (true or false) in local state.
  • Event Listener – Listens for the change event; when the user resizes the window, the state updates automatically.

Real‑World Example: Sidebar vs. Sheet

Now, let’s see how to use this hook to solve the “Sidebar vs. Sheet” problem. We want to render a completely different UI structure depending on the device.

import { useState } from "react";
import { useMediaQuery } from "./hooks/use-media-query";

export function CourseSidebar({
  course,
  currentLessonId,
  onLessonSelect,
  collapsed = false,
  onToggle,
}: Props) {
  const [isSheetOpen, setIsSheetOpen] = useState(false);

  // Define your breakpoint here
  const isMobile = useMediaQuery("(max-width: 768px)");

  // 1. Render Mobile View (Sheet/Modal)
  if (isMobile) {
    return (
      <Sheet open={isSheetOpen} onOpenChange={setIsSheetOpen}>
        <SheetTrigger>
          <Button>Menu</Button>
        </SheetTrigger>
        <SheetContent>
          {/* Your Menu Items */}
        </SheetContent>
      </Sheet>
    );
  }

  // 2. Render Desktop View (Standard Sidebar)
  return (
    <aside>
      {/* Your Menu Items */}
    </aside>
  );
}

Why This Is Better

By using if (isMobile), we perform conditional rendering:

  • On mobile, the desktop sidebar is never rendered to the DOM.
  • On desktop, the mobile Sheet code is ignored.

This keeps the application lighter and faster, and prevents bugs where mobile event listeners might fire while in desktop view.

Summary

CSS is for styling; JavaScript is for logic. When you need to change what is rendered based on the viewport, reach for window.matchMedia. This simple useMediaQuery hook bridges the gap between your CSS breakpoints and your React component logic.

For more information, visit my website.

Back to Blog

Related posts

Read more »

Under the hood: React

Introduction I've wanted to do this since the moment I started using React: understand what makes it tick. This is not a granular review of the source code. In...

React using Calculator

Today i completed one of the pratice project on React Using calculator.This React Calculator application performs basic arithmetic operations. It supports butto...