matchMedia().addListener marked as deprecated, addEventListener equivalent?
Asked Answered
C

4

96

I'm making use of matchMedia().addListener to detect dark/light mode theme preference changes in Safari, however in WebStorm using addListener is marked as deprecated but simply says to refer to documentation for what should replace it.

I've had a read through the MDN docs and I don't understand what event type I should be listening for in addEventListener to replace addListener?

window.matchMedia("(prefers-color-scheme: dark)").addListener(() => this.checkNative());
window.matchMedia("(prefers-color-scheme: light)").addListener(() => this.checkNative());
Cablet answered 5/6, 2019 at 18:39 Comment(0)
R
136

From the doc - https://developer.mozilla.org/en-US/docs/Web/API/MediaQueryList/addListener

A function or function reference representing the callback function you want to run when the media query status changes.

It should be change event. https://developer.mozilla.org/en-US/docs/Web/API/MediaQueryList/onchange.

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

mql.addEventListener("change", () => {
    this.checkNative();
});
Reger answered 5/6, 2019 at 18:45 Comment(8)
TypeError: window.matchMedia("(prefers-color-scheme: dark)").addEventListener is not a function.Cablet
What you get in mql?Reger
It's a MediaQueryList as expectedCablet
@MattCowley - I do not have much idea about matchMedia, but the example provided in developer.mozilla.org/en-US/docs/Web/API/MediaQueryList/… window.matchMedia('(max-width: 600px)'); works perfectly.Reger
Ah, looks like this isn't supported in Safari yet, yet addListener is. How odd...Cablet
Similar issue with iPhone 6s running IOS 13.4.1 - logs error addEventListener is not a function. Had to revert code to deprecated addListener() to get Angular web app to work on both Safari and Chrome on iPhone. Any ideas what changed?Upthrust
FYI: at time of writing a patch has landed in WebKit to address this, just isn't in Safari yet: bugs.webkit.org/show_bug.cgi?id=203288Farewell
@MattCowley Not odd at all. Safari is terrible at following W3C standards.Maley
T
66

Chrome and Firefox handle it differently than Safari, I solved it with way:

const darkMediaQuery = window.matchMedia('(prefers-color-scheme: dark)');

  try {
    // Chrome & Firefox
    darkMediaQuery.addEventListener('change', (e) => {
      this.$vuetify.theme.dark = !this.$vuetify.theme.dark;
    });
  } catch (e1) {
    try {
      // Safari
      darkMediaQuery.addListener((e) => {
        this.$vuetify.theme.dark = !this.$vuetify.theme.dark;
      });
    } catch (e2) {
      console.error(e2);
    }
  }

If you're interested in how to support Dark Mode with your website, read this blogpost.

Theresita answered 31/1, 2020 at 9:3 Comment(3)
I notice that we're using addListener again here, which is triggering a typescript deprecation warning.Cryptozoic
@AnnKilzer Yep, that's because Safari doesn't yet support the new API so you are forced to use the (deprecated) addListener method if you want to support Safari.Valuer
Looks like safari supports addEventListener('change', ... as of version 14 (see developer.mozilla.org/en-US/docs/Web/API/MediaQueryList/…). Current version is 15, so this was adopted ~November 12, 2020.Douceur
A
5

If you just do as MDN writes it works cross browser (where it's supported):

const mql = window.matchMedia('(max-width: 767px)');
mql.onchange = (e) => { 
  /* ... */
}

Should be supported above IE. E.g. all Edge + modern browsers.

https://developer.mozilla.org/en-US/docs/Web/API/MediaQueryList/onchange

Acetify answered 26/11, 2021 at 13:47 Comment(4)
onchange is only supported starting with Safari 14, so it doesn't seem to offer any benefit compared to addEventListener. I.e. if you want to support Safari 14+ you can use addEventListener, if you need to support Safari 13 or below you need to do a check like in @Szabó Csaba's answerMegalith
@Megalith all companies I've worked at only support last 2 major versions of browsers, e.g. iOs 14 and 15. Supporting more takes a lot of resources, especially with IE and older safari versionsAcetify
Fair enough on which browsers you want to support - I'm not arguing you need to support older browsers. I'm just pointing out that the OP asked when to use "addEventListener to replace addListener". onChange doesn't seem to give you any advantage relative to addEventListener since it also is iOS 14+, and thus doesn't answer the question. If you're on iOS 14+ use addEventListener (or `onChange if you prefer that style) otherwise you have to check.Megalith
I can't remember exactly now but it was either ie11, ios14 or android, samsung browser? addEventListener method did not work and only .onchange method that's why MDN and I used it.. so the benifit is that one worked crossbrowser and the other did NOT! I haven't checked the status todayAcetify
F
0

Based On Szabó Csaba Answer

const darkMediaQuery = window.matchMedia('(prefers-color-scheme: dark)');

function onPrefersColorScheme(status: MediaQueryListEvent): void {
  // TODO
}

function tryChromeandFirefox() {
  darkMediaQuery.addEventListener('change', onPrefersColorScheme);
}

function trySafari() {
  darkMediaQuery.addListener(onPrefersColorScheme);
}

try {
  tryChromeandFirefox();
} catch {
  try {
    trySafari();
    // eslint-disable-next-line no-empty
  } catch {}
}

Also, single-line trying to invoke (not recommended):

// add `async` to
async function tryChromeandFirefox();
async function trySafari();

tryChromeandFirefox().catch(() => trySafari());
Felisafelise answered 14/2 at 10:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.