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
Fundamentals
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.
Concept
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.
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
Hands-On
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.");
}
≥ 600px → Viewport width is at least 600 pixels.
< 600px → Viewport width is less than 600 pixels.
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);
Now at least 600px wide.
(or)
Now less than 600px wide.
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.");
}
Reduce motion ON → Skipping animation — reduced motion preferred.
Reduce motion OFF → Playing intro animation.
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.
Applications
🚀 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.
Important
📝 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.
Compatibility
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 ChromeAll versions · Desktop & Mobile
Full support
Mozilla FirefoxAll versions · Desktop & Mobile
Full support
Apple SafariAll versions · macOS & iOS
Full support
Microsoft EdgeAll versions · Chromium & Legacy
Full support
Internet ExplorerIE 6+ · Legacy environments
Full support
OperaAll modern versions
Full support
matchMedia()Universal
Bottom line: Use addEventListener('change') instead of the legacy addListener method in new code.
Wrap Up
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.
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
Summary
Key Takeaways
Knowledge Unlocked
Five things to remember about matchMedia()
Your foundation for responsive JavaScript in the browser.
5
Core concepts
📝01
Syntax
matchMedia(query)
API
✅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.