One of the more recent features available in browsers is ability to
do CSS Media Queries
based on user
theme & accessibility settings in the operating system - for example using
@media (prefers-color-scheme: dark)
you can check if the users OS theme is currently in Dark Mode and use this to set a websites theme accordingly.
function - that returns a
MediaListQuery that will allow us to do two things:
- The current value of the users setting via the
- Any future values by listening to its
changesevent and attaching an event lister function to it
Combining these, it’s the perfect candidate to turn into a fully reactive dark mode switcher using RxJS and Observables that will give us the users current setting. If you’re not familiar with Observables, they are a type of stream that emits values over time - consumers can subscribe to these Observables to get their values - this means we can use them to get values from long running functions or event emitters.
In the full demo you’ll find an example page with light and dark mode set from your own OS settings. To see the full
working example you need to change the setting (e.g. in OSX Dark Mode is under “General” settings) - also provided are a
user toggle button, and a button to turn off and on the media query listener. The Observable in this example supports
more than one
prefers- type of query but in the tutorial below we’ll build a much simpler
isDarkMode Observable than
the one provided in the demo, but the concept is the same.
Creating a Dark Mode Observable
For our code we first need to create our Observable factory - this is our function that allows us to pass any required parameters for the implementation and returns an Observable which can then be subscribed to.
The Observable constructor takes a function - a callback any time there is a new subscription - this is where the implementation will live.
As soon as the subscription opens, we first check to see if
window.matchMedia is available - it should be available in
all modern browsers but is not available in environments like node (yay unit testing!) - so here we can throw an error.
The factory also accepts an optional AbortSignal
object that contains an
onabort callback - the parent of the signal is
and using this we can externally
signal our Observable to close all subscriptions and remove all event listeners.
The return value of the constructor is another function - the teardown logic - this is called when an RxJS subscription
is ended, such as using
take(1) - here we also ensure that all subscriptions and event listeners are
Adding the Media Query
The main implementation of our Observable is to create our
MediaListQuery and use it to emit values to any
subscribers. On creation, contain a
matches value of
false which can be immediately be passed to
We also need to bind a listener using to the
change event of the query. As we also need to remove this later create an
internal private function for the event handler - this will also call
subscriber.next each time there is a detected
Also casting the event to a
MediaQueryListEvent ensures TypeScript recognises it has the
matches property which
contains our value.
Cleaning up handlers and subscriptions
Already we can start to use the new Observable, but we also need to make sure that we:
- End any subscriptions to the Observable when either the
AbortSignalfires or RxJS unsubscribes from it
- Remove any event listeners in the DOM for the
With a slight bit of refactoring we have our final Observable factory below - in both the
signal.onabort and the
Observable teardown logic we remove the event listener - the API for this requires you pass the function implementation
from our private function.
Now we have a fully working reactive Observable for a Dark Mode media query, this can be used in any application or website to check the users theme setting. The demo provides some more example of how to do this in full.
This tutorial is just one small example of the kind of things that can be done with RxJS - any API that can emit values over time can be turned into Observables.
A collection of pre-built operators and Observables for your projects
Still in active development, you might find useful operators that provide clearer intent for your RxJS code.
You can check out the source code on GitHub .