
Responsive JavaScript and the matchMedia Method

We've all worked with JavaScript functions that should do different things at different screen sizes, on different devices or in different browsers, or based on certain user preferences.
And there are many established ways of handling that in JavaScript, although it always feels a little hacky, and often comes at the cost of additional weight on the client, resulting in a more 'janky' experience.
In the past, to work out the dimensions of a document we would check window.innerWidth on every resize event, as well as on page load. As you might imagine, there is a better, more performant, and neater way of achieving this:
The matchMedia() method
This was a pleasant discovery, and I don't mind admitting that I might have come across this one a little later than some.
The often‑overlooked matchMedia() JavaScript method is a handy‑dandy way of using CSS media query syntax (e.g., (min‑width: 1024px)) directly within JavaScript. It also means that we can use the same CSS syntax in our JavaScript to detect any of the other various browser or user preferences that media types or media features encompass.
This is clearly a much neater and more concise way of handling different visitor types, characteristics, preferences, or parameters.
The neatness of your code isn't the only benefit, however; matchMedia is also significantly more performant than tying event listeners and measures to the window or document. The method even comes with its own listener. And, surprisingly, it's really well supported, assuming that you are ok only supporting Internet Explorer 10 and up.
At this point, I want to quickly stress just how powerful matchMedia can be for detecting media features. Although I only intend to focus on screen sizes today, just remember that anything you can do with a media query in CSS, you can also do with matchMedia.
Setting up the Media Query
Getting matchMedia() up and running is super simple; it's literally three lines of code (four if you really want to count that trailing bracket):
const isDesktop = window.matchMedia('(min-width: 1024px)');if (isDesktop.matches) { console.log('viewport above 1024px!');}So, what's that .matches property? matchMedia() returns a MediaQueryList object (you can check out some more in‑depth docs on that type of object here), which has its own methods and properties. .matches is one of those properties and contains a boolean value of either true or false, depending on whether the media query is matched.
However, to get this media query working the same way that a regular CSS query would work (i.e actually responsively, on window size change), we'll need to use one of the methods that MediaQueryList exposes to us.
The change event
const isDesktop = window.matchMedia('(min-width: 1024px)');isDesktop.addEventListener('change', e => { if (e.matches) { console.log('viewport above 1024px!'); }});That media query is now listening responsively to every resize, and you can check against the query by using the .matches property. Super easy, super neat, and easy to understand at a glance.
However, we're not quite done. As with any other event‑based functionality, this won't trigger on the initial page load, so we've no idea whether the media query matches or not until some other external influence causes it to trigger. For example: if the user resizes the window. So, in order to get this running and working as you would expect it to, we still need to trigger it.
If we extract out our resize‑handling function, then triggering it could look like the code below, although you would almost certainly want to make sure the page is ready before triggering, maybe inside a useEffect() hook, or ‑ if you're still using jQuery ‑ inside of $(document).ready() 🤮.
const isDesktop = window.matchMedia('(min-width: 1024px)');const handleResize = e => { if (e.matches) { console.log('viewport above 1024px!'); }};// handles our media query as/when it changesisDesktop.addEventListener('change', e => handleResize(e));// instantiates the media query at load-timehandleResize(isDesktop)A note on the .addListener() method
Previously, you would have achieved the same as the above by using the .addListener() method, and you will likely find plenty of code examples that use that instead of .addEventListener(). The example above would then have looked something more like this:
const isDesktop = window.matchMedia('(min-width: 1024px)');const handleResize = e => { if (e.matches) { console.log('viewport above 1024px!'); }};isDesktop.addListener(handleResize);This method has been depreciated for a long while now, and although some browsers may still support it, it's wise not to use it. Anyway: using the change event is so much neater!
The Wrap‑Up
matchMedia() is a neater, more performant, and heavily under‑appreciated way to handle the pretty common obstacle of building JavaScript that responds to differing media states in the document.
It opens the door for more accessible functionality by exposing a simple way to use CSS media queries like prefers‑reduced‑motion or prefers‑contrast, and is widely supported by browsers. It's definitely a method that should get a little more love!
Related Articles

Unravelling JavaScript: Commonly Misunderstood Methods and Features. 
Understanding the Module Pattern in JavaScript. Understanding the Module Pattern in JavaScript

Understanding JavaScript's sort() Method. Understanding JavaScript's
sort()Method
Integrating CMSes with HTML, CSS, and JavaScript. Integrating CMSes with HTML, CSS, and JavaScript

Event Delegation in JavaScript. Event Delegation in JavaScript

Custom _app and Custom _document in Next.js. Custom
_appand Custom_documentin Next.js
Repetitive Asynchronous Tasks with JavaScript's setInterval(). Repetitive Asynchronous Tasks with JavaScript's
setInterval()
Understanding the JavaScript Event Loop. Understanding the JavaScript Event Loop

Intervals in Practice: Solving the 'Merge Intervals' Problem. Intervals in Practice: Solving the 'Merge Intervals' Problem

How to Handle Multiple Named Exports in One JavaScript File. How to Handle Multiple Named Exports in One JavaScript File

How to Find a Programmer Job. How to Find a Programmer Job

Monotonic Stack: Solving the 'Daily Temperatures' Problem. Monotonic Stack: Solving the 'Daily Temperatures' Problem