JAVASCRIPT

Detect and React to DOM Changes with MutationObserver

Understand how to use MutationObserver to efficiently monitor and react to changes in the DOM structure, element attributes, or text content in real-time.

function observeDOMChanges(targetElementId, callback) {
  const targetNode = document.getElementById(targetElementId);
  if (!targetNode) {
    console.error(`Target element with ID "${targetElementId}" not found.`);
    return null;
  }

  // Options for the observer (which types of mutations to observe)
  const config = { attributes: true, childList: true, subtree: true, characterData: true };

  // Create an observer instance linked to the callback function
  const observer = new MutationObserver((mutationsList, observer) => {
    for (const mutation of mutationsList) {
      console.log(`Mutation Type: ${mutation.type}`);
      if (mutation.type === 'childList') {
        console.log('A child node has been added or removed.', mutation.addedNodes, mutation.removedNodes);
      } else if (mutation.type === 'attributes') {
        console.log(`The "${mutation.attributeName}" attribute was modified.`, mutation.target);
      } else if (mutation.type === 'characterData') {
        console.log('The text content was modified.', mutation.target);
      }
    }
    callback(mutationsList, observer); // Pass mutations to the user-defined callback
  });

  // Start observing the target node for configured mutations
  observer.observe(targetNode, config);

  console.log(`MutationObserver started for element #${targetElementId}.`);

  return observer; // Return the observer instance to allow disconnecting later
}

// Example Usage:
// Assume HTML: <div id="container"></div>

const myContainerCallback = (mutations, observerInstance) => {
  console.log('Custom callback triggered for container changes!');
  // Example: If a new paragraph is added, do something
  mutations.forEach(mutation => {
    if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {
      mutation.addedNodes.forEach(node => {
        if (node.nodeType === Node.ELEMENT_NODE && node.tagName === 'P') {
          console.log('New paragraph added:', node.textContent);
          node.style.border = '1px solid green';
        }
      });
    }
  });
  // Optionally disconnect observer after a certain condition
  // if (someCondition) {
  //   observerInstance.disconnect();
  //   console.log('MutationObserver disconnected.');
  // }
};

const containerObserver = observeDOMChanges('container', myContainerCallback);

// Simulate DOM changes after a delay
setTimeout(() => {
  const container = document.getElementById('container');
  const p1 = document.createElement('p');
  p1.textContent = 'First dynamically added paragraph.';
  container.appendChild(p1);
}, 1000);

setTimeout(() => {
  const p1 = document.querySelector('#container p');
  if (p1) p1.setAttribute('data-status', 'processed');
}, 2000);

setTimeout(() => {
  const p2 = document.createElement('p');
  p2.textContent = 'Second paragraph.';
  container.appendChild(p2);
}, 3000);

setTimeout(() => {
  const p2 = document.querySelectorAll('#container p')[1];
  if (p2) p2.textContent = 'Second paragraph updated!';
}, 4000);

// To stop observing later:
// if (containerObserver) {
//   setTimeout(() => {
//     containerObserver.disconnect();
//     console.log('Observer explicitly disconnected after 5 seconds.');
//   }, 5000);
// }
How it works: This snippet illustrates the use of `MutationObserver` to asynchronously monitor changes to the DOM. It creates an observer that watches a specified target element and its subtree for modifications like additions/removals of child nodes (`childList`), changes to attributes (`attributes`), or alterations in text content (`characterData`). When changes occur, the provided callback function is executed with a list of `MutationRecord` objects, allowing developers to react precisely to dynamic DOM updates. This is particularly useful for integrating with third-party scripts, debugging, or building highly reactive user interfaces without constant polling.

Need help integrating this into your project?

Our team of expert developers can help you build your custom application from scratch.

Hire DigitalCodeLabs