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
MutationObserveris 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
// 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
<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
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:
| Property | Description |
|---|---|
type | the type of change (attributes, childList, characterData) |
target | the element where the change happened |
addedNodes | added elements |
removedNodes | removed elements |
attributeName | the name of the changed attribute |
oldValue | the old value of the attribute or text |
5. Stopping the observation
To stop watching:
observer.disconnect();To pause temporarily and turn it back on:
observer.takeRecords(); // returns the accumulated changes
observer.observe(...); // can be turned back on6. 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):
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
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
MutationObserverworks 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: trueon the wholedocument, that can be expensive.
Summary
| What it does | MutationObserver |
|---|---|
| Tracks | Changes in the DOM (attributes, text, adding/removing elements) |
| Replaces | The old DOMNodeInserted, DOMSubtreeModified events |
| Works | Asynchronously, through the microtask queue |
| Used for | Dynamic UI, integrations, watching React/Vue, animations, custom components |
| Control | observe(), disconnect(), takeRecords() |
Remember it simply:
MutationObserveris a "DOM guard": it watches for changes in the tree and reports what, where, and when something changed, without constant checks orscrollevents.
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.