MutationObserver and ResizeObserver
By Flavio Copes
Use MutationObserver to watch DOM changes and ResizeObserver to track element size changes, with practical examples and cleanup via disconnect().
Browsers give you two observer APIs for reacting to page changes. MutationObserver watches the DOM tree, attributes, and text. ResizeObserver watches element size.
They replace older hacks like polling or listening to window resize for every layout tweak.
MutationObserver
A MutationObserver runs a callback when nodes are added, removed, or changed.
You pass a target element and an options object. Common flags are childList, attributes, and subtree.
const list = document.querySelector('#comments')
const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
mutation.addedNodes.forEach((node) => {
if (node.nodeType !== Node.ELEMENT_NODE) return
console.log('New comment added:', node.textContent)
})
})
})
observer.observe(list, {
childList: true,
subtree: true
})
This fires when someone appends a new comment node inside #comments.
Set attributes: true if you care about class or style changes on the target. Add attributeFilter: ['class'] to limit noise.
A practical example: detecting added nodes
Say a chat app injects messages into a container. You want to scroll to the bottom on each new message.
const chat = document.querySelector('#chat')
const observer = new MutationObserver(() => {
chat.scrollTop = chat.scrollHeight
})
observer.observe(chat, { childList: true })
No need to hook into every function that adds a message. The observer catches all of them.
ResizeObserver
ResizeObserver fires when an element’s content box changes size. It is more precise than a window resize event.
const sidebar = document.querySelector('#sidebar')
const observer = new ResizeObserver((entries) => {
entries.forEach((entry) => {
const { width, height } = entry.contentRect
console.log(`Sidebar is ${width}x${height}`)
})
})
observer.observe(sidebar)
Use this when a chart, canvas, or sticky panel must reflow after its container shrinks or grows.
A window resize listener misses cases where only one panel changes, like a collapsible sidebar. ResizeObserver catches those.
When to use each
| Observer | Watches |
|---|---|
| MutationObserver | DOM tree changes, attribute changes |
| ResizeObserver | Element width and height |
Use MutationObserver for dynamic lists, third-party widgets that inject HTML, or syncing state when the DOM changes.
Use ResizeObserver for charts, maps, custom scroll areas, and any layout that depends on element dimensions.
Cleanup with disconnect()
Both observers keep watching until you stop them. Call disconnect() when your component unmounts or no longer needs updates.
mutationObserver.disconnect()
resizeObserver.disconnect()
My advice is to store the observer in a variable and disconnect it in the matching cleanup code. An observer you no longer need can keep callbacks and referenced state alive.
Related posts about platform: