Skip to main content

How does MutationObserver work?

MutationObserver is a browser-built-in API that lets you watch for changes in the DOM: adding, removing, or changing the attributes or text of elements, and react to that in real time.

This is a powerful alternative to old events like DOMSubtreeModified (which are deprecated and used to slow the page down).


Definition

MutationObserver is a special object that "watches" an element and reports when something changes in it (structure, attributes, text, and so on).

It works asynchronously, does not block the interface, and calls a callback when changes occur in the observed node.


1. Basic example

javascript
// Create the observer const observer = new MutationObserver((mutations) => { mutations.forEach(mutation => { console.log('Change type:', mutation.type); }); }); // The element we will watch const target = document.querySelector('#app'); // Observation settings observer.observe(target, { childList: true, // watch for adding/removing child elements attributes: true, // watch for attribute changes subtree: true // watch everything inside the element });

Now, if you add a new element to #app or change an attribute, a message about the type of change appears in the console.


2. A live example

javascript
<div id="box">Hello!</div> <button id="btn">Change</button> <script> const box = document.getElementById('box'); const btn = document.getElementById('btn'); const observer = new MutationObserver((mutations) => { mutations.forEach(m => console.log(m)); }); observer.observe(box, { childList: true, attributes: true, characterData: true }); btn.addEventListener('click', () => { box.textContent = 'Text changed!'; box.setAttribute('data-status', 'updated'); }); </script>

On click, MutationRecord objects appear in the console, containing information about:

  • the type of change (attributes, childList, characterData);
  • which attribute changed;
  • the old and new value (if enabled).

3. observe() settings

javascript
observer.observe(target, { childList: true, // adding/removing child elements attributes: true, // attribute changes characterData: true, // text changes inside nodes subtree: true, // watch descendants (the whole tree) attributeFilter: ['class', 'style'], // watch only these attributes attributeOldValue: true, // keep the old attribute value characterDataOldValue: true // keep the old text value });

4. What MutationRecord contains

Each element of the mutations array is a MutationRecord object with properties:

PropertyDescription
typethe type of change (attributes, childList, characterData)
targetthe element where the change happened
addedNodesadded elements
removedNodesremoved elements
attributeNamethe name of the changed attribute
oldValuethe old value of the attribute or text

5. Stopping the observation

To stop watching:

javascript
observer.disconnect();

To pause temporarily and turn it back on:

javascript
observer.takeRecords(); // returns the accumulated changes observer.observe(...); // can be turned back on

6. Example: watching for dynamic insertions

A very common case, catching new elements added by a JS framework (for example, React, Vue, or someone else's script):

javascript
const container = document.querySelector('#feed'); const observer = new MutationObserver((mutations) => { mutations.forEach(m => { m.addedNodes.forEach(node => { if (node.nodeType === 1 && node.matches('.post')) { console.log('New post added:', node.textContent); } }); }); }); observer.observe(container, { childList: true, subtree: true });

Now, when a <div class="post">...</div> is added dynamically, JS reacts instantly.


7. Example: automatically reacting to a class change

javascript
const box = document.querySelector('#box'); const observer = new MutationObserver((entries) => { for (const mutation of entries) { if (mutation.attributeName === 'class') { console.log('Class changed to:', box.className); } } }); observer.observe(box, { attributes: true });

This is handy for tracking state changes, for example during animations or toggle effects.


8. Performance

  • MutationObserver works asynchronously: changes are "batched" and delivered together, not on every pixel or character.
  • This makes it very efficient even with a large number of observations.
  • But do not overuse subtree: true on the whole document, that can be expensive.

Summary

What it doesMutationObserver
TracksChanges in the DOM (attributes, text, adding/removing elements)
ReplacesThe old DOMNodeInserted, DOMSubtreeModified events
WorksAsynchronously, through the microtask queue
Used forDynamic UI, integrations, watching React/Vue, animations, custom components
Controlobserve(), disconnect(), takeRecords()

Remember it simply: MutationObserver is a "DOM guard": it watches for changes in the tree and reports what, where, and when something changed, without constant checks or scroll events.

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.