MutationObserver Options Reference

childList, attributes, subtree and characterData options with callback entry shape.

Reference for MutationObserver observe() options — childList, attributes, characterData, subtree and the OldValue and filter flags — plus every MutationRecord property and a live config validator.

Why does observe() throw on my config?

MutationObserver.observe requires at least one of childList, attributes or characterData to be true. A config with only subtree or only the OldValue flags is invalid because there is nothing concrete to watch, so the call throws a TypeError.

Watching the DOM for changes

MutationObserver reports DOM changes — added or removed nodes, attribute edits and text changes — asynchronously and in batches, replacing the deprecated Mutation Events. Its behaviour is driven entirely by the options object passed to observe() and read through the MutationRecord entries in your callback. This reference covers both, with a validator for the must-have-one-of-three rule.

How it works

You create an observer with a callback, then call observe(target, options):

const mo = new MutationObserver((records) => {
  for (const r of records) {
    if (r.type === "childList") console.log(r.addedNodes, r.removedNodes);
    if (r.type === "attributes") console.log(r.attributeName, r.oldValue);
  }
});

mo.observe(node, {
  childList: true,
  attributes: true,
  attributeOldValue: true,
  subtree: true,
});

At least one of childList, attributes or characterData must be true or observe() throws. subtree widens the scope to all descendants, and the *OldValue and attributeFilter flags implicitly turn on their related option. The callback runs as a microtask with a coalesced batch of records.

Tips and notes

  • A config with only subtree: true is invalid — pair it with at least one concrete flag.
  • attributeFilter limits noise by reporting only the named attributes you care about.
  • Disconnect with mo.disconnect() when done, and mo.takeRecords() drains any pending queue.
  • Beware feedback loops: mutating the DOM inside the callback can re-trigger the observer.