Suggest an editImprove this articleRefine the answer for “How does MutationObserver work?”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)**`MutationObserver`** is a built-in API that asynchronously watches an element and calls a callback whenever its structure (`childList`), attributes (`attributes`), or text (`characterData`) changes. **Key point:** it does not block the interface, delivers changes in batches through the microtask queue, and is controlled with `observe()`, `disconnect()`, and `takeRecords()`.Shown above the full answer for quick recall.Answer (EN)Image`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: | 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: ```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 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:** > `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.For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.