How to ‘listen’ for attribute changes in JavaScript

It’s nice to have event listeners for events on elements, but how do you listen for something like an attribute change?

Enter MutationObserver. One of its best qualities is enabling you the ability to watch data not otherwise capable of being “listened” to, like a traditional DOM event.

First, set up the function that will be called by MutationObserver. It takes just one argument: mutationsList. Each item in the list is what’s called a MutationRecord. The callback can do anything you want.

const mutationCallback = (mutationsList) => {
for (const mutation of mutationsList) {
if (
mutation.type !== "attributes" ||
mutation.attributeName !== "data-foo"
) {
return
}
console.log('old:', mutation.oldValue)
console.log('new:', mutation.target.getAttribute("data-foo"))
}
}

Next, the MutationObserver takes your callback when initializing the instance:

const observer = new MutationObserver(mutationCallback)

Of course, we haven’t actually kicked off the observer yet. just call the observe method on your new variable. Its arguments are the element to observe and an object describing the data you’re observing:

observer.observe(myElement, { attributes: true })

Finally, you can stop observing the changes using the disconnect method:

observer.disconnect()

And that’s it. Easy, right? Well, just be careful; it can be tempting to create new mutation observers for every little thing. Instead, try to consolidate as much as you can into one observer. You can add subtree: true when calling the observe method to listen for changes to child nodes, too!

Check out the full range of options for observable data here.

If you liked what you read, feel free to obliterate that like button. ✅

George is a front-end developer and digital designer living in Oregon. By day, he’s a software engineer on ServiceNow’s design systems team. By night, he is constantly re-arranging his video game collection as a distraction from finally playing one.

Learning to see. @gwtrev