🐝 Tjoskar's Blog

I write about stuff, mostly for myself

Media query in JavaScript and React 🖼️

Let’s say you want to know if the user in on a small device or not, or if the user prefers darkmode or reduce motion. And you want to know that from javascript. You might also want to get updated when the values change. Here is where matchMedia enters the stage.matchMedia lets you execute a media query string against the document and get the result back.

Get preferd color scheme from js

Let’s say you want to know if the user prefer darkmode. In css this can easily be done with:

@media (prefers-color-scheme: dark) {
  /** The user want it dark  */
}

We can do almoste the same in javascript with matchMedia:

const match = window.matchMedia("(prefers-color-scheme: dark)");

And that is not just true for color scheme, but for all media querys:
const colorSchemeMatch = window.matchMedia("(prefers-color-scheme: dark)");
const smallScreen = window.matchMedia("(max-width: 600px)");

console.log(`Wants darkmode: \${colorSchemeMatch.matches ? 'yes' : 'no'`);
console.log(`Is on small device: \${smallScreen.matches ? 'yes' : 'no'`);

We can also gets updates when the match changes:

const smallScreen = window.matchMedia("(max-width: 1000px)");
const onSmallScreenSizeChange = (e) => {
  console.log(`Is on small device: ${e.matches ? "yes" : "no"}`);
};
console.log(`Is on small device: ${smallScreen.matches ? "yes" : "no"}`);

smallScreen.addEventListener("change", onSmallScreenSizeChange);

// Later on:
smallScreen.removeEventListener("change", onSmallScreenSizeChange);

Use matchMedia with react

It can be quite handy to use matchMedia in react, and can be done with a simple hook:

import { useState, useEffect } from 'react';

const useMatchMedia = (query: string) => {
  const [match, setMatch] = useState<boolean>(() => {
    return window.matchMedia(query).matches;
  });

  useEffect(() => {
    const queryMatch = window.matchMedia(query);
    const updateMatch = (match: MediaQueryListEvent) => {
      setMatch(() => match.matches);
    };
    queryMatch.addEventListener('change', updateMatch);
    return () => queryMatch.removeEventListener('change', updateMatch);
  }, [query]);

  return match;
};

function MyComponent() {
  const wantDarkmode = useMatchMedia('(prefers-color-scheme: dark)');
  return <p>{ wantDarkmode ? 🌙 : ☀️ }</p>;
}
Dragon Plane