useMutationObserver
Observe DOM mutations like added/removed nodes, attribute changes, and text modifications using the MutationObserver API.
Approach 1: Single Element
Observe one element for DOM changes. Detects child additions/removals and attribute changes.
Add/remove items or change attributes to see mutations detected
Observed Container
Mutation Log (last 10)
No mutations detected yet
Approach 2: Multiple Elements
One observer tracking multiple elements. More efficient for monitoring many containers.
Single Observer tracking multiple containers
Add or remove items from any box
Box 1
Box 2
Box 3
Mutation Log (last 10)
No mutations detected yet
Code Examples
Single Element
import { useMutationObserver } from "@uiblock/hooks";
export default function Demo() {
const ref = useMutationObserver(
(mutations) => {
mutations.forEach((mutation) => {
if (mutation.type === 'childList') {
console.log('Children changed!');
}
if (mutation.type === 'attributes') {
console.log('Attribute changed:', mutation.attributeName);
}
});
},
{
childList: true,
attributes: true,
subtree: true
}
);
return <div ref={ref}>Observed content</div>;
}Multiple Elements
import { useMutationObserverMultiple } from "@uiblock/hooks";
import { useRef, useEffect } from "react";
export default function Demo() {
const { observe } = useMutationObserverMultiple(
(mutations) => {
mutations.forEach((mutation) => {
const id = mutation.target.getAttribute('data-mutation-id');
console.log(`Mutation in ${id}`);
});
},
{ childList: true }
);
const box1Ref = useRef(null);
const box2Ref = useRef(null);
useEffect(() => {
if (box1Ref.current) observe(box1Ref.current, 'box1');
if (box2Ref.current) observe(box2Ref.current, 'box2');
}, [observe]);
return (
<div>
<div ref={box1Ref}>Box 1</div>
<div ref={box2Ref}>Box 2</div>
</div>
);
}Mutation Types
childList: trueObserve additions and removals of child nodes
attributes: trueObserve changes to element attributes (class, style, data-*, etc.)
characterData: trueObserve changes to text content
subtree: trueObserve all descendants, not just direct children
attributeOldValue: trueRecord the previous value of changed attributes
How It Works
Here's the implementation:
import { useEffect, useRef } from 'react'
export function useMutationObserver(callback, options?) {
const ref = useRef(null)
const callbackRef = useRef(callback)
useEffect(() => {
callbackRef.current = callback
}, [callback])
useEffect(() => {
const element = ref.current
if (!element) return
const observer = new MutationObserver((mutations, observer) => {
callbackRef.current(mutations, observer)
})
observer.observe(element, options)
return () => observer.disconnect()
}, [options])
return ref
}Multiple Elements Version
For observing multiple elements with a single observer:
import { useEffect, useRef, useCallback } from 'react'
export function useMutationObserverMultiple(callback, options?) {
const observerRef = useRef(null)
const callbackRef = useRef(callback)
useEffect(() => {
callbackRef.current = callback
}, [callback])
useEffect(() => {
observerRef.current = new MutationObserver((mutations, observer) => {
callbackRef.current(mutations, observer)
})
return () => observerRef.current?.disconnect()
}, [])
const observe = useCallback((element, id) => {
if (!element || !observerRef.current) return
element.setAttribute('data-mutation-id', id)
observerRef.current.observe(element, options)
}, [options])
return { observe }
}API Reference
useMutationObserver
Parameters
callback: MutationCallbackFunction called when mutations occur
options?: MutationObserverInitConfiguration (childList, attributes, characterData, subtree, etc.)
Returns
ref - Ref to attach to the element to observe
useMutationObserverMultiple
Parameters
callback: MutationCallbackFunction called when mutations occur
options?: MutationObserverInitConfiguration options
Returns
observe(element, id) - Function to observe an element with a unique ID
💡 Use Cases
- Detecting when content is dynamically added/removed
- Monitoring third-party widget changes
- Tracking attribute changes for analytics
- Syncing UI state with DOM changes
- Building dev tools and debugging utilities
- Implementing undo/redo functionality