JavaScript Window matchMedia() Method

Beginner
⏱️ 8 min read
📚 Updated: Jul 2026
🎯 5 Examples
🚀 5 Try-it labs
Responsive JS

What You’ll Learn

The matchMedia() method lets JavaScript test the same media queries you use in CSS. This tutorial covers syntax, the MediaQueryList object, listening for change events, five examples, and patterns for responsive UI and user preferences.

01

Syntax

matchMedia(query)

02

Return

MediaQueryList

03

.matches

true or false

04

Listen

change event

05

CSS sync

Same @media syntax

06

Prefs

Dark mode, motion

Introduction

Responsive websites adapt layout with CSS @media rules. Sometimes JavaScript also needs to know whether a breakpoint matches— to swap components, load a mobile menu module, or respect the user’s dark-mode preference. window.matchMedia() bridges CSS media queries and JavaScript logic.

Instead of comparing raw pixel widths with window.innerWidth, you pass a media query string like "(min-width: 768px)". The browser returns a MediaQueryList whose matches property tells you the current result, and whose change event fires when that result flips.

Understanding the matchMedia() Method

Call window.matchMedia(mediaQueryString) with a valid media query (usually wrapped in parentheses). The return value is a live MediaQueryList object—not a boolean. Read mediaQueryList.matches for the yes/no answer at this moment.

Register addEventListener("change", handler) on that object so your script reacts when the user resizes the window, rotates a phone, or changes system settings that affect the query.

💡
Beginner Tip

Keep one MediaQueryList in a variable and reuse it. Avoid calling matchMedia() on every pixel of a resize handler—listen for change instead.

📝 Syntax

General form of Window.matchMedia():

JavaScript
const mq = window.matchMedia(mediaQueryString);
// shorthand (same in browsers):
const mq = matchMedia("(min-width: 768px)");

Parameters

  • mediaQueryString (required) — a string containing a media query, e.g. "(max-width: 767px)" or "(prefers-color-scheme: dark)".

Return value

  • A MediaQueryList with at least:
    • matches — boolean, whether the query is true now.
    • media — the query string you passed.

Common patterns

  • if (matchMedia("(min-width: 600px)").matches) { … } — one-time check.
  • mq.addEventListener("change", onChange) — respond to updates.
  • matchMedia("(prefers-reduced-motion: reduce)").matches — accessibility preference.

⚡ Quick Reference

TopicDetail
Call formwindow.matchMedia("(min-width: 768px)")
Check nowmq.matches
On changemq.addEventListener("change", fn)
Remove listenermq.removeEventListener("change", fn)
Dark mode pref(prefers-color-scheme: dark)
Applies CSS?No — JS reads; CSS @media applies styles

📋 matchMedia() vs innerWidth vs CSS alone

CSS handles most responsive layout. Use matchMedia when JavaScript must branch on the same conditions.

matchMedia
mq.matches

Full media query syntax

innerWidth
innerWidth > 768

Pixels only

CSS @media
@media (min-width)

Styles without JS

change
addEventListener

Better than resize spam

Examples Gallery

Each snippet tests a media query and logs or updates UI based on matches. Resize the Try-it preview or change system theme to see change events fire.

📚 Getting Started

Create a MediaQueryList and read matches once.

Example 1 — Check a Minimum Width

Test whether the viewport is at least 600 pixels wide.

JavaScript
const mediaQuery = window.matchMedia("(min-width: 600px)");

if (mediaQuery.matches) {
  console.log("Viewport width is at least 600 pixels.");
} else {
  console.log("Viewport width is less than 600 pixels.");
}
Try It Yourself

How It Works

The browser evaluates the query against the current viewport. matches is a boolean you can use in if statements immediately.

📈 Practical Patterns

Listeners, mobile breakpoints, and user preference queries.

Example 2 — Listen for Query Changes

Run logic when the match result flips—resize the window to trigger it.

JavaScript
const mediaQuery = window.matchMedia("(min-width: 600px)");

function handleChange(mq) {
  if (mq.matches) {
    console.log("Now at least 600px wide.");
  } else {
    console.log("Now less than 600px wide.");
  }
}

handleChange(mediaQuery);
mediaQuery.addEventListener("change", handleChange);
Try It Yourself

How It Works

The handler receives the MediaQueryList as its event target context; read event.matches or the list’s matches inside the callback. Prefer this over deprecated addListener.

Example 3 — Mobile Layout Branch

Use max-width to detect smaller screens and adjust JavaScript behavior.

JavaScript
const mobileQuery = window.matchMedia("(max-width: 767px)");

if (mobileQuery.matches) {
  console.log("Mobile layout — enable compact menu.");
} else {
  console.log("Desktop layout — show full navigation.");
}
Try It Yourself

How It Works

Align the breakpoint with your CSS @media (max-width: 767px) rules so styles and scripts switch at the same width.

Example 4 — Respect Dark Mode Preference

Query the user’s color-scheme preference from the operating system or browser.

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

if (darkModeQuery.matches) {
  console.log("Dark mode preference detected.");
  document.body.classList.add("theme-dark");
} else {
  console.log("Light mode preference detected.");
  document.body.classList.remove("theme-dark");
}
Try It Yourself

How It Works

prefers-color-scheme reflects OS/browser settings. Add a change listener if your app should update live when the user toggles theme.

Example 5 — Reduced Motion Preference

Skip heavy animations when the user prefers reduced motion.

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

function runIntroAnimation() {
  if (reduceMotion.matches) {
    console.log("Skipping animation — reduced motion preferred.");
    return;
  }
  console.log("Playing intro animation.");
}

runIntroAnimation();
Try It Yourself

How It Works

Accessibility settings flow into media queries. Checking prefers-reduced-motion in JS keeps carousels, parallax, and auto-play consistent with CSS that disables transitions.

🚀 Common Use Cases

  • Responsive components — mount mobile vs desktop widgets at the same breakpoint as CSS.
  • Conditional loading — import heavy chart libraries only on large screens.
  • Dark / light themes — sync JavaScript charts or maps with prefers-color-scheme.
  • Accessibility — honor prefers-reduced-motion and prefers-contrast.
  • Orientation — detect (orientation: landscape) for canvas games or video players.
  • Analytics — log which breakpoint bucket the user is in without polling resize constantly.

🧠 What Happens When You Call matchMedia()

1

Parse query

Browser reads the media query string you pass in.

Parse
2

Evaluate

Viewport size, orientation, and preferences are tested.

Match
3

MediaQueryList

Object returned with matches true or false.

Result
4

Live updates

When conditions change, change fires on the same list—your handler runs again.

📝 Notes

  • Prefer CSS for layout changes; use JS when behavior—not just appearance—must change.
  • The change event handler receives a MediaQueryListEvent with a matches property.
  • Invalid query strings may throw or match nothing—test queries in DevTools first.
  • matchMedia is not available in Node.js without a DOM; use it in browsers.
  • Combine multiple conditions: "(min-width: 768px) and (prefers-reduced-motion: no-preference)".
  • Remove listeners in single-page apps when components unmount to avoid leaks.

Browser Support

Window.matchMedia() and MediaQueryList.addEventListener('change') are supported in all modern browsers. It is the standard way to bridge CSS media queries and JavaScript.

Universal · Standard API

Window.matchMedia()

Supported in Chrome, Firefox, Safari, Edge, Opera, and mobile browsers—including preference queries like prefers-color-scheme.

100% Universal support
Google Chrome All versions · Desktop & Mobile
Full support
Mozilla Firefox All versions · Desktop & Mobile
Full support
Apple Safari All versions · macOS & iOS
Full support
Microsoft Edge All versions · Chromium & Legacy
Full support
Internet Explorer IE 6+ · Legacy environments
Full support
Opera All modern versions
Full support
matchMedia() Universal

Bottom line: Use addEventListener('change') instead of the legacy addListener method in new code.

Conclusion

window.matchMedia() lets JavaScript ask the same responsive questions CSS already answers. Read matches for a snapshot, listen for change to stay in sync as the viewport or user preferences evolve.

Pair it with CSS breakpoints, respect accessibility media features, and avoid reinventing width checks with raw pixel math unless you have a specific reason.

💡 Best Practices

✅ Do

  • Reuse one MediaQueryList per query string
  • Use addEventListener("change", …) for updates
  • Match breakpoints with your CSS @media rules
  • Honor prefers-reduced-motion and color-scheme prefs
  • Remove listeners when components are destroyed

❌ Don’t

  • Call matchMedia() on every resize event
  • Use deprecated addListener in new projects
  • Assume matchMedia changes CSS by itself
  • Hard-code pixel widths when a media query expresses intent better
  • Forget to run initial logic before attaching the listener

Key Takeaways

Knowledge Unlocked

Five things to remember about matchMedia()

Your foundation for responsive JavaScript in the browser.

5
Core concepts
02

.matches

Boolean now.

Read
🔄 03

change

Live updates.

Event
📱 04

Breakpoints

Same as CSS.

Sync
🌙 05

Prefs

Dark, motion.

A11y

❓ Frequently Asked Questions

It evaluates a CSS media query string and returns a MediaQueryList object. You read query.matches to see if the condition is true right now—for example whether the viewport is at least 600px wide.
Yes. Pass the condition inside parentheses, such as '(min-width: 768px)' or '(prefers-color-scheme: dark)'. JavaScript and CSS then stay in sync.
Call mediaQueryList.addEventListener('change', handler). The handler runs when the user resizes the window or when system preferences like dark mode change.
addListener was the older API. Modern code should use addEventListener('change', fn). removeEventListener cleans up when you are done.
innerWidth is just a pixel number. matchMedia() understands full media query syntax—orientation, prefers-reduced-motion, hover capability, and compound conditions.
No. It only reports whether a query matches. Your JavaScript decides what to do—toggle classes, load modules, or update UI text.
Did you know?

Before matchMedia(), developers often listened to the window resize event and compared innerWidth manually. Media query lists fire only when a specific condition crosses true/false—not on every pixel of drag.

Continue to moveBy()

Learn how to move a browser window by a relative offset with window.moveBy().

moveBy() tutorial →

About the author

Mari Selvan M P
Mari Selvan M P 🔗

Developer, cloud engineer, and technical writer

  • Experience 12 years building web and cloud systems
  • Focus Full Stack Development, AWS, and Developer Education

I write practical tutorials so students and working developers can learn by doing—from databases and APIs to deployment on AWS.

6 people found this page helpful