|$ curl https://forge-ai.dev/api/markdown?path=docs/web-platform/mutation-observer
$cat docs/mutation-observer.md
updated Recently·22 min read·published

Mutation Observer

Web PlatformIntermediate🎯Free Tools
Introduction

Mutation Observer watches for changes to the DOM tree — added/removed nodes, attribute changes, and text content modifications. It replaced the deprecated Mutation Events API and fires callbacks asynchronously in batches, making it far more performant.

Basic Usage
basic-observer.ts
TypeScript
1// Create a Mutation Observer
2const observer = new MutationObserver((mutations) => {
3 for (const mutation of mutations) {
4 if (mutation.type === "childList") {
5 console.log("Nodes added:", mutation.addedNodes.length);
6 console.log("Nodes removed:", mutation.removedNodes.length);
7 }
8 if (mutation.type === "attributes") {
9 console.log("Attribute changed:", mutation.attributeName);
10 console.log("Old value:", mutation.oldValue);
11 }
12 if (mutation.type === "characterData") {
13 console.log("Text content changed:", mutation.target.textContent);
14 }
15 }
16});
17
18// Start observing
19observer.observe(document.getElementById("app")!, {
20 childList: true, // Watch for added/removed nodes
21 attributes: true, // Watch for attribute changes
22 characterData: true, // Watch for text content changes
23 subtree: true, // Watch all descendants (not just direct children)
24 attributeOldValue: true, // Record previous attribute values
25 attributeFilter: ["class", "style"], // Only watch specific attributes
26});
27
28// Stop observing
29observer.disconnect();
30
31// Get pending mutations (not yet delivered)
32const records = observer.takeRecords();
Practical Use Cases
use-cases.ts
TypeScript
1// Use Case 1: Auto-save form content
2const form = document.querySelector("form")!;
3const autoSaveObserver = new MutationObserver(() => {
4 const data = new FormData(form);
5 localStorage.setItem("draft", JSON.stringify(Object.fromEntries(data)));
6});
7
8autoSaveObserver.observe(form, {
9 childList: true,
10 subtree: true,
11 characterData: true,
12 attributes: true,
13});
14
15// Use Case 2: Detect dynamically added elements
16const listObserver = new MutationObserver((mutations) => {
17 for (const mutation of mutations) {
18 for (const node of mutation.addedNodes) {
19 if (node instanceof HTMLElement && node.classList.contains("new-item")) {
20 initItem(node); // Initialize new items
21 }
22 }
23 }
24});
25
26listObserver.observe(document.getElementById("list")!, {
27 childList: true,
28 subtree: true,
29});
30
31// Use Case 3: React to class/style changes (e.g., theme switching)
32const themeObserver = new MutationObserver((mutations) => {
33 for (const mutation of mutations) {
34 if (mutation.attributeName === "class") {
35 const isDark = document.documentElement.classList.contains("dark");
36 updateThemeIcon(isDark);
37 }
38 }
39});
40
41themeObserver.observe(document.documentElement, {
42 attributes: true,
43 attributeFilter: ["class"],
44});

info

Always call observer.disconnect() when the observed element is removed (e.g., in React useEffect cleanup). Undisconnected observers leak memory.
React Patterns
react-hook.tsx
TypeScript
1// React hook for Mutation Observer
2import { useEffect, useRef } from "react";
3
4function useMutationObserver(
5 callback: (mutations: MutationRecord[]) => void,
6 options: MutationObserverInit = { childList: true, subtree: true }
7) {
8 const ref = useRef<Node>(null);
9
10 useEffect(() => {
11 if (!ref.current) return;
12 const observer = new MutationObserver(callback);
13 observer.observe(ref.current, options);
14 return () => observer.disconnect();
15 }, [callback, options]);
16
17 return ref;
18}
19
20// Usage
21function AutoSaveEditor() {
22 const ref = useMutationObserver(
23 (mutations) => {
24 console.log("Content changed, auto-saving...");
25 // Debounce save logic here
26 },
27 { childList: true, subtree: true, characterData: true }
28 );
29
30 return <div ref={ref} contentEditable suppressContentEditableWarning />;
31}
$Blueprint — Engineering Documentation·Section ID: WP-MO-01·Revision: 1.0