window.matchMedia() — Media Queries in JavaScript

You already know how to handle events. Now use a browser media query to choose JavaScript behavior and respond when that condition changes. Review CSS Media Queries if the query syntax is unfamiliar.

1. What does matchMedia() do?

window.matchMedia() takes a media-query string and returns a MediaQueryList object. Its matches property tells you whether the query currently matches: true or false.

const wideScreen = window.matchMedia("(min-width: 768px)");
console.log(wideScreen.matches);

Here, 768 CSS pixels or wider gives true. Below 768 gives false. This checks viewport width, not the physical screen size or device type. The breakpoint is an example you can choose to suit your layout.

2. Read the expression step by step

window            // the browser window object
.matchMedia(...)  // call its method with a query string
.matches          // read a Boolean property on the returned object

Keep the parentheses around a media feature such as (min-width: 768px). Do not include @media or CSS braces in the string. matches is a property, so write .matches, not .matches().

const wideScreen = window.matchMedia("(min-width: 768px)");

if (wideScreen.matches) {
  console.log("Use the wide layout behavior");
} else {
  console.log("Use the narrow layout behavior");
}

3. CSS styling and JavaScript behavior

Use CSS media queries for responsive styling, such as columns and spacing. Use matchMedia when JavaScript needs to respond to the same condition, for example closing a mobile menu when the wide navigation becomes available.

/* CSS */
@media (min-width: 768px) {
  .cards { display: flex; }
}

Calling matchMedia does not apply CSS or automatically update your interface. Your code decides what action to take.

4. Listen for changes — live example

Resize the browser across 768 CSS pixels. The message below shows the initial result and updates when the query switches between matching and not matching.

Enable JavaScript to run this example.

<p id="media-query-result" role="status"></p>
const query = window.matchMedia("(min-width: 768px)");
const output = document.querySelector("#media-query-result");

function updateResult() {
  output.textContent = query.matches
    ? "Matches: viewport is at least 768 CSS pixels wide."
    : "Does not match: viewport is below 768 CSS pixels wide.";
}

updateResult();
query.addEventListener("change", updateResult);

Place the script after the paragraph, or load an external script with defer. The first call to updateResult() sets the initial text. Registering a listener does not call it immediately. The change listener runs when the match result changes, rather than for every pixel of resizing.

5. Read the change event

const query = window.matchMedia("(min-width: 768px)");

function handleChange(event) {
  console.log(event.matches); // the new Boolean result
  console.log(event.media);   // the media-query string
}

query.addEventListener("change", handleChange);

This listener belongs to the MediaQueryList object. It is not a form change event. You can read event.matches inside the callback or read query.matches from the saved object.

6. Remove a listener when it is no longer needed

query.removeEventListener("change", handleChange);

For the preceding example, this stops future calls to handleChange. Use the same query object and function reference used when registering. Run cleanup when removing the feature that owns the listener. For the live example, the callback name is updateResult.

7. Respect reduced-motion preferences

The site also uses a media query to check reduced-motion preferences. This example makes an optional reveal effect immediate when reduced motion is requested:

const reduceMotion = window.matchMedia(
  "(prefers-reduced-motion: reduce)"
).matches;

const heading = document.querySelector("h1");

heading.animate(
  [{ opacity: 0 }, { opacity: 1 }],
  { duration: reduceMotion ? 0 : 300 }
);

Here reduceMotion holds the Boolean value read at that moment. It does not update by itself. For an ongoing feature that must respond to preference changes, keep the MediaQueryList object and use its change event, as in the live example.

8. Common mistakes

9. Practice

Change the live-example query to (min-width: 1024px) and update its messages. Predict the output at 1023 and 1024 CSS pixels, then check it. Next, try (prefers-reduced-motion: reduce) and change the emulated preference in browser developer tools.

Expected width results: false at 1023 and true at 1024. For the preference query, true means reduced motion is requested.

10. Quick reference

const query = window.matchMedia("(min-width: 768px)");
query.matches;                         // current result
query.addEventListener("change", fn);   // observe changes
query.removeEventListener("change", fn); // stop observing

In this reference, fn means the same callback function you defined earlier.

References: MDN: window.matchMedia() and MDN: MediaQueryList change event.

← Back