πŸ‘οΈ MutationObserver live

A single MutationObserver watches the target element below for every type of mutation. Use the controls to trigger changes β€” each one fires the observer and appears in the log with its full MutationRecord.

1 Observed target element
This element is being watched with { childList: true, attributes: true, characterData: true, subtree: true }
child-1 child-2
The highlight flash is applied to the wrapper around this element, not to the element itself β€” writing an attribute on an observed node from inside the callback makes the observer call itself forever.
Children: 2 data-status: none
2 Trigger mutations
childList β€” add or remove a child node
attributes β€” change an attribute on the target
characterData β€” edit a text node directly
3 MutationRecord log
No mutations yet β€” use the controls above…
4 The code running this demo
const target = document.getElementById('target'); let counter = 3; const observer = new MutationObserver((mutations) => { for (const mutation of mutations) { // mutation.type β†’ 'childList' | 'attributes' | 'characterData' // mutation.target β†’ the node that changed // mutation.addedNodes β†’ NodeList of added nodes (childList only) // mutation.oldValue β†’ previous value (if attributeOldValue/ // characterDataOldValue was set) logMutation(mutation); } }); observer.observe(target, { childList: true, subtree: true, attributes: true, characterData: true, attributeOldValue: true, characterDataOldValue: true, });
5 Why not just poll?
Aspect MutationObserver setInterval polling
Timing Fires immediately after the change Up to N ms late (interval gap)
CPU when idle Zero β€” no polling cost Runs every tick regardless
Batching Multiple changes β†’ one callback No batching; multiple checks may run
Detail Full record: type, target, old value Must diff DOM yourself
Cleanup observer.disconnect() clearInterval() (easy to forget)