Skip to content
usefy

useMutationObserver

Layout & observers

Watch an element for DOM mutations — child, attribute, and character-data changes — with the MutationObserver API

Install

$ npm install @usefy/use-mutation-observer

Quick start

useMutationObserver.tsx
import { useMutationObserver } from "@usefy/use-mutation-observer";

function Watched() {
  const { ref, records } = useMutationObserver<HTMLDivElement>({
    childList: true,
    subtree: true,
    onMutation: (mutations) => {
      for (const m of mutations) console.log(m.type, m.target);
    },
  });

  return <div ref={ref}>{records.length} recent mutations</div>;
}

API reference

useMutationObserver<T>(options?)

Observes the element attached via the returned ref for DOM mutations.

Options — UseMutationObserverOptions<T>

OptionTypeDefaultDescription
childListbooleantrue*Observe additions/removals of the target's child nodes
attributesbooleanfalseObserve attribute changes (implied true when attributeFilter/attributeOldValue is set)
attributeFilterstring[]Only observe the named attributes (implies attributes: true)
attributeOldValuebooleanfalseRecord the previous attribute value in MutationRecord.oldValue (implies attributes)
characterDatabooleanfalseObserve character-data changes
characterDataOldValuebooleanfalseRecord the previous character data in oldValue (implies characterData)
subtreebooleanfalseExtend observation to the whole subtree, not just direct children
onMutation(mutations: MutationRecord[], observer: MutationObserver) => voidCallback fired with each batch of records (stored in a ref — safe to pass inline)
enabledbooleantrueWhen false, disconnects and stops reporting; flip back to true to re-observe
updateStatebooleantrueWhether to mirror the latest batch into the records state. false = callback-only

* childList defaults to true only when none of childList/attributes/characterData is enabled — the DOM API requires at least one.

Returns — UseMutationObserverReturn<T>

PropertyTypeDescription
ref(element: T | null) => voidCallback ref to attach to the target; null disconnects
recordsreadonly MutationRecord[]The latest batch of records (empty until the first mutation)
isSupportedbooleanWhether the MutationObserver API is available
isObservingbooleanWhether the hook is currently observing an element
observe(element: T) => voidManually start observing an element (escape hatch alongside ref)
disconnect() => voidDisconnect the observer, stopping all observation
takeRecords() => MutationRecord[]Flush and return any queued-but-undelivered records

Note: MutationObserver has no per-target unobserve; disconnect() (dropping all observation) is the only way to stop, matching the native API.

disconnect() is terminal: after calling it, re-attaching the same ref does not restart observation (the ref only re-observes when the element changes, and the internal observer is torn down). To resume, call observe(element) again, or remount the component.

Also exported: isMutationObserverSupported() and resolveMutationConfig(options) (pure helpers), the EMPTY_RECORDS sentinel, and the UseMutationObserverOptions, UseMutationObserverReturn, OnMutationCallback types.

Go deeper

This page is the quick reference. For every example, prop, and edge case, read the full README — or open Storybook to change props live.

More in layout & observers