# JS Tip of the Day: MutationObserver

**URL:** <https://forum.kirupa.com/t/js-tip-of-the-day-mutationobserver/643095>\
**Category:** web dev\
**Created:** [May 11, 2020, 12:32pm UTC](https://forum.kirupa.com/t/js-tip-of-the-day-mutationobserver/643095 "2020-05-11T12:32:40Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![senocular](https://yyz1.discourse-cdn.com/flex011/user_avatar/forum.kirupa.com/senocular/32/7217_2.png) [@senocular](https://forum.kirupa.com/u/senocular)\
**Post date:** [May 11, 2020, 12:32pm UTC](https://forum.kirupa.com/t/js-tip-of-the-day-mutationobserver/643095/1 "2020-05-11T12:32:40Z")

</div>

**MutationObserver**  
Level: Intermediate

The Web API has a number of observer utilities that allow you to watch for changes or certain occurrences that happen within the DOM or web browser. One of these is the MutationObserver. It allows you to watch for changes in DOM elements including:

- Adding or removing of child elements
- Changes in element text
- Adding, removing, or changing of attributes

A MutationObserver works somewhat like a cross between a proxy and `addEventListener()`. When created, it takes a single callback which gets notified when mutations occur. Then, from the MutationObserver instance, you can observe certain elements in the DOM that will in turn trigger the callback when mutations are recognized.

```javascript
let observer = new MutationObserver(callback);
observer.observe(element, options);

```

The options passed to `observe()` indicate what mutations are being watched for and how the results of those mutations are reported back to the observer’s callback. Options include:

- attributeFilter
- attributeOldValue
- attributes
- characterData
- characterDataOldValue
- childList
- subtree

Consider the following super-intricate and absolutely revolutionary web app that adds kittens to the screen when you click.

```javascript
addEventListener('click', event => {
    if (event.shiftKey) {
        if (event.target.tagName === 'IMG') {
            event.target.remove();
        }
    } else {
        let width = 170;
        let height = 170;
        let img = document.createElement('IMG');
        img.src = `https://placekitten.com/${width}/${height}`;
        Object.assign(img.style, {
            position: 'absolute',
            left: (event.clientX - width / 2) + 'px',
            top: (event.clientY - height / 2) + 'px'
        });
        document.body.appendChild(img);
    }
});

```

If someone wanted to add analytics to report on when the user added or removed kittens using this code, it could be instrumented to do so, modified to add hooks into each of those different operations allowing them send out messages to the appropriate logging systems. However, since the changes ultimately boil down to DOM updates, all of that can be skipped in favor of using a MutationObserver. With a MutationObserver, you can spy directly on the DOM without having to dig into the implementation of the existing code that’s making the changes to it. Here is how that might look.

```javascript
let imgAnalytics = new MutationObserver(mutations => {
    for (let mutation of mutations) {
        for (let added of mutation.addedNodes) {
            if (added.tagName === 'IMG') {
                console.log('User added image');
            }
        }
        for (let removed of mutation.removedNodes) {
            if (removed.tagName === 'IMG') {
                console.log('User removed image');
            }
        }
    }
});
imgAnalytics.observe(document.body, {
    childList: true
});

```

This `imgAnalytics` MutationObserver will log to the console whenever an image element is added or removed from the `document.body` element, acting as analytics reporting for the soon-to-be wonderfully successful and lucrative click for kittens app.

More info:

- [MutationObserver on MDN](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver)
