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: trueis invalid — pair it with at least one concrete flag. attributeFilterlimits noise by reporting only the named attributes you care about.- Disconnect with
mo.disconnect()when done, andmo.takeRecords()drains any pending queue. - Beware feedback loops: mutating the DOM inside the callback can re-trigger the observer.