Web Debugging: Watching Element Changes

Recently, I was debugging a regression where I wanted to watch change’s in an element’s property at runtime. Specifically, I wanted to watch the URL change when I select different colors in Tesla’s customizer. By using the Inspect Element tool, I can find the relevant image in the tree, and then when I pick a different color in the page, the Developer Tools briefly highlight the changes to the image’s attributes:

Unfortunately, you might notice that the value in the xlink:href property contains a ... in the middle of it, making it difficult to see what’s changed. I noted that the context menu offers a handy “Break on” submenu to break execution whenever the node changes:

…but I lamented that there’s no Watch attribute command to log the changing URLs to the console. Mozillian April King offered a helpful snippet that provides this functionality.

After selecting the image (which points Console variable $0 at the element), type the following in the Console:

new MutationObserver(i => console.log(i[0].target.attributes['xlink:href'])).observe($0,
{ attributes: ['xlink:href']});

This simple snippet creates a MutationObserver to watch the selected element’s xlink:href attribute, and every time it changes, the callback writes the current attribute value to the console:

Cool, huh?

Thanks, April!


Published by ericlaw

Impatient optimist. Dad. Author/speaker. Created Fiddler & SlickRun. PM @ Microsoft 2001-2012, and 2018-2022, working on Office, IE, and Edge. Now a SWE on Microsoft Defender Web Protection. My words are my own, I do not speak for any other entity.

One thought on “Web Debugging: Watching Element Changes

  1. MutationObserver is definitely cool. Here’s another snippet that I use to allow the callback to make changes to the observed element without causing an overflow:

    class MutationHelper {

    constructor(handler, opts) {
    this.#handler = handler || console.info.bind(console);
    this.#opts = opts || { childList:true, subtree:true, attributes: true, characterData:false };
    this.#observer = new MutationObserver(this.#callback.bind(this));

    #callback(records) {
    // detach observer in case #handler makes DOM changes
    // return false from #handler to stop receiving events.
    if (this.#handler.call(this.#element, records) === false) {
    // re-attach observer
    this.#observer.observe(this.#element, this.#opts);

    observe(element) {
    this.#element = element;
    this.#observer.observe(this.#element, this.#opts);

    new MutationHelper(myFunctionThatAddsElements).observe(document.body);

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: