JS MutationObserver
In this page:
What Is MutationObserver?
MutationObserver watches a DOM element for changes. It can detect added, removed, and changed nodes. This is useful for reacting to DOM changes made by other code (like a third-party widget) that you can't hook into directly with your own event handlers.
Example: What Is MutationObserver?
<div id="box">Original</div>
<script>
const observer = new MutationObserver(() => console.log("Something changed"));
observer.observe(document.getElementById("box"), { childList: true, attributes: true, characterData: true, subtree: true });
document.getElementById("box").textContent = "Changed";
</script>
Watching Added Nodes
The childList option lets you detect when child nodes are added or removed. This lets you react specifically to structural changes — like a new item appearing in a list — without also being notified about unrelated style or attribute updates.
Example: Watching Added Nodes
<ul id="list"><li>Item 1</li></ul>
<script>
const observer = new MutationObserver((mutations) => console.log("Nodes changed:", mutations.length));
observer.observe(document.getElementById("list"), { childList: true });
const li = document.createElement("li");
li.textContent = "Item 2";
document.getElementById("list").appendChild(li);
</script>
Watching Attribute Changes
The attributes option detects changes to element attributes such as class or data attributes. This is commonly used to detect when a class toggled by other code (like a loading or active state) actually changes.
Example: Watching Attribute Changes
<div id="box" class="idle">Status</div>
<script>
const observer = new MutationObserver(() => console.log("Class changed:", document.getElementById("box").className));
observer.observe(document.getElementById("box"), { attributes: true });
document.getElementById("box").className = "active";
</script>
Watching Text Changes
The characterData option watches changes to text nodes. subtree can include descendants. This combination is what lets you detect edits to visible text content, which wouldn't otherwise trigger a childList or attributes mutation.
Example: Watching Text Changes
<p id="text">Hello</p>
<script>
const observer = new MutationObserver(() => console.log("Text changed"));
observer.observe(document.getElementById("text"), { characterData: true, subtree: true });
document.getElementById("text").firstChild.textContent = "Updated";
</script>
Stopping an Observer
Call disconnect when you no longer need an observer. This avoids unnecessary work. Because observers keep running (and consuming resources) until explicitly stopped, disconnecting one you no longer need is good practice, not just an optimization.
Example: Stopping an Observer
<div id="box">Content</div>
<script>
const observer = new MutationObserver(() => console.log("Changed"));
observer.observe(document.getElementById("box"), { childList: true });
observer.disconnect(); // stop watching, avoids unnecessary work
document.getElementById("box").textContent = "Never logged";
</script>
Chapter Quiz — Complete all 8 topics to unlock
0/8 topics done
Complete these topics first: