Skip to content

Observe changes to the DOM using an async iterable — A nicer API for MutationObserver

License

Notifications You must be signed in to change notification settings

sindresorhus/dom-mutations

Repository files navigation

dom-mutations

Observe changes to the DOM using an async iterable — A nicer API for MutationObserver

This package only works in the browser.

Install

npm install dom-mutations

Usage

import domMutations from 'dom-mutations';

const target = document.querySelector('#unicorn');

for await (const mutation of domMutations(target, {childList: true})) {
	console.log('Mutation:', mutation);
}

API

domMutations(target, options?) (default export)

Accepts the same arguments as MutationObserver#observe() with an additional optional signal option to abort the observation. If the signal is triggered, the async iterable throws an abort error.

Returns an AsyncIterable that yields MutationRecord objects representing individual mutations.

batchedDomMutations(target, options?) (named export)

Similar to domMutations(), but yields batches of MutationRecord objects, each batch representing a group of mutations captured together. This method is less convenient, but can be useful in some cases when you need to handle mutations together as a group.

import {batchedDomMutations} from 'dom-mutations';

const target = document.querySelector('#unicorn');

for await (const mutations of batchedDomMutations(target, {childList: true})) {
	console.log('Batch of mutations:', mutations);
}

FAQ

How do I stop the iteration?

Simply return or break in the loop body.

How do I stop the iteration from the outside?

Triggering the iterator to return

import domMutations from 'dom-mutations';

const target = document.querySelector('#unicorn');

const mutationIterator = domMutations(target, {childList: true})[Symbol.asyncIterator]();

(async () => {
	for await (const mutation of mutationIterator) {
		console.log('Mutation:', mutation);
	}
})();

setTimeout(() => {
	mutationIterator.return();
}, 10000);

Using a variable

This has the downside of not ending the iteration until the next mutation.

import domMutations from 'dom-mutations';

const target = document.querySelector('#unicorn');

let shouldStop = false;

(async () => {
	for await (const mutation of domMutations(target, {childList: true})) {
		if (shouldStop) {
			break;
		}

		console.log('Mutation:', mutation);
	}
})();

setTimeout(() => {
	shouldStop = true;
}, 10000);

Using AbortController

Unlike the above approaches, this will make the iterable throw an abort error.

import domMutations from 'dom-mutations';

const target = document.querySelector('#unicorn');
const controller = new AbortController();
const {signal} = controller;

(async () => {
	for await (const mutation of domMutations(target, {childList: true, signal})) {
		console.log('Mutation:', mutation);
	}
})();

setTimeout(() => {
	controller.abort();
}, 10000);

Related