Easily observe changes in DOM tree with MutationObserver API

Easily observe changes in DOM tree with MutationObserver API

Photo by mostafa meraji on Unsplash

You might find yourself need to know when the DOM has changed so you can eg. trigger a function. That could be to show a notification or send a fetch request to an API. You might not know when the tree is triggered or you do not have any control over some parts of your system because of the existing components og API’s from a third party that trigger the DOM tree mutation. Therefore you need a way to observe individual elements and fire a function when those elements are mutated. This is what the Mutation Observer API is used for.

The mutation observer API, is a fully supported feature on all browsers (including IE 11) in which you can observe individual html elements and know when the element has changed (eg. an attribute is added or child node is removed/added). This is useful when you want to execute a function based on this.

The Mutation Observer API is a relative new API which is a replacement for the MutationEvent API that is now deprecated.

A real world example, was when i had to integrate a modal component onto a page where the modal was imported from a third party library. The modal components did not have a onClose or onOpen callback event or similar that was called when the modal is open/closed. The component did set an attribute on the body element called “modal-open”, which was used internally by the component to determine if the modal is open or not.

To solve this issue we can use the Mutation Observer with the following:

// Create an observer instance linked to the callback function
const observer = new MutationObserver(callback);

// Start observing the target node for configured mutations
observer.observe(document.getElementsByTagName("body"), { attributes: true });

// Later, you can stop observing
observer.disconnect();

We instantiate the MutationObserver with a callback function that contains the logic we want to fire when a mutation has been observed. Second line contains Observer.observe which takes in 2 arguments. First argument is the element you want to observe. In this situation we want to observe the body element. Second argument is the options argument in which you can configure the mutationobserver which type of mutation should trigger the callback function. That way we can limit the callback function to only be called when the attributes on the body element is changed. If we didn’t provide any config, then it will throw an TypeError. If we provided the subtree option, then every time a child of the body element is mutated, then the callback is triggered. Sine the body element is a wrapper element for most html elements, then it will get triggered alot of times.

You can find the full list of available attributes on mdn here

Whenever you don’t want to observe anymore on the body element, we can call the disconnect function and the mutationobserver will stop observing.

const callback = function (mutationsList) {
for (const mutation of mutationsList) {
if (mutation.type === "attributes") {
if(mutation.attributeName.includes("modal-open")) {
showNotification("Modal open");
}
}
}
};

The callback contains a mutationsList parameter which contains a list of all the mutations on the element. You can filter the mutation by its type, and see eg. which attribute has changed with the attributeName. There are many other ways you can use the mutation observer, and perhaps you already have some ideas for some technical challenges that the MutationObserver API can help you with.