Understanding the MutationObserver API

This browser API gives us cool features you should use. It might seem scary, but I promise you it's not!

Emil Hein
Better Programming

--

The DOM and the MutationObserver

The MutationObserver, is a lot like the IntersectionObserver, as I described here, in the way the API works. Except for having a similar name, the two API’s output is very different.
The MutationObserver is supported in most big browsers, and therefore you can start utilizing its functionality.

So what's it all about?

Changes in the DOM!

While this sounds pretty simple, it can also be extremely powerful. With this feature, you can detect if specific elements are being inserted, removed, or the attributes of an element changes.

Without using this API, relatively simple tasks have a lot of edge cases, and performance might vary depending on your implementation. Using a standard browser API can ensure performance and stability out of the box.

Some Use Cases

  • You want to run some code if some elements are inserted asynchronously
  • You want to detect a “page-change” in a single-page application
  • You don’t have control of certain insertions of HTML elements, let's say, from a third-party library
  • You have a third-party ibrary implemented on a site, and you want to know when the site inserts a certain element on the page

The last example is the way I got introduced to the API.

How To Use It

In the same way that the IntersectionObserver API is a bit funky to work with, we can easily create a small wrapper that, in my opinion, makes it a bit smoother to work with. The native implementation requires three parameters:

  1. An HTML element (can be the entire body)
  2. A configuration object that determines some specifics (see here)
  3. A callback function that will be executed whenever the API registers a change that meets your configuration params (1 and 2)
MutationObserver wrapper

I’m defaulting the configuration and the element to check in the above wrapper. What this configuration does is watch the entire document body for changes. subtree: true will make sure that we look through nested insertions or deletions.

If you already know a subelement where you want to look for changes, it's more performant to give a more specific selector than document.body.
For simplicity, the above wrapper only needs a callback function that will be triggered whenever any element is changed.

MutationObserver callback function

This might look a bit nested and scary, but don’t mind that for now.
The above will check for all nodes added to the DOM. If the node has an id=’color-node’, it will wait 200ms and change the background to orange.

An example

Now, let's say we are the producers of a third-party library that changes the div elements with a specific id to a certain color after they’re inserted into the site. Now, we have no control over how the site is implemented. It might be a SPA or a WordPress site.

The site might insert the elements using their own JavaScript or another library for it.

For simplicity’s sake, let's assume the site inserts a specific node in a regular interval. Now our dummy library will change the background color of the inserted nodes.

A simple implementation, changing the color as elements are inserted

In the above example, I’m simulating that the site inserts nine div elements with an interval of 500ms. In real life, that’s unlikely to happen. But that’s the beauty of the MutationObserver. It will trigger your callback function whenever an element is inserted, deleted, or changed.

Note: As with the IntersectionObserver, it's important to use the disconnect method when you no longer wish to subscribe to mutations in the DOM.

SPA URL change

In another small use case, we use the MutationObserver to detect page changes in a single-page application. Now, since they don’t do a real browser page change but use internal routing, our script will not be loaded and executed like on a “normal” website.

With the MutationObserver, we can look for changes in the DOM (a SPA router change) and check the location.href against the previous to decide if the SPA has changed its view. After this, we should rerun our core code logic. A simple example could look like this:

Detect change in SPA URL

Final Notes

As someone who maintains a library implemented on many sites, using the MutationObserver helps us have a unified API for handling asynchronous insertions or deletions in the DOM.

In our case, we need to react whenever the site inserts a specific div element.

If a new div element meets a set of criteria, we will insert our “product” into that div element.

Now, since the MutationObserver triggers our callback on all insertions, it doesn’t matter if the client has an infinite scroll that keeps adding elements or if it happens by the click of a button.

Together with the IntersectionObserver API, it’s super easy to handle certain DOM things without implementing a lot of custom code.

Both APIs have been available for quite some time, but I feel adoption is still pretty low.

It might be because of old Stack Overflow answers or their scary names.

Thanks for reading! Stay tuned for more.

--

--

Fullstack developer. I enjoy prototyping and testing new services. I like working with JavaScript, Nodejs, AWS and Vue, Browser API's, adtech, Go + more