javascriptdommutation-observersmutation-events

What is the most efficient way of detecting when an element with a particular ID is inserted in the DOM


As the title suggests, I want to detect the exact timestamp when an element with a particular id or CSS class is inserted into the DOM (and possibly detect when it is removed). The most obvious method is to poll the document periodically, by calling document.getElementById with the id of the element I want to find, but this method is not very accurate and can be very performance intensive if I have multiple elements I want to detect.

I took a look at Mutation Events and Mutation Observers, but from what I understand, in order to detect if an element is inserted or removed, I have to add a listener to the root DOM element, which can heavily impact performance if I need to execute additional JS each time an element is inserted or removed from the page.

Is there a more optimized solution that I am not aware of? Also, I would prefer if I didn't use an external JS library, even jQuery.


Solution

  • It turns out there is a more efficient way to detect when a particular node is inserted, by using CSS animation events.

    You can define an unnoticeable animation to the class you are listening for, lets say widget_inserted:

    @keyframes widget_inserted {  
        from { z-index: 1; }
        to { z-index: 1; }   
    }
    
    .widget {
        animation-duration: 0.001s;
        animation-name: widget_inserted;
    }
    

    I've chosen the z-index property because in most cases it should have virtually no added effects on the element which is inserted. Combined with a very short animation duration, these added CSS properties should produce no additional changes to the original document.

    So now if you attach an animationstart event listener to the document, you should be able to catch the exact moment when an element with the widget class is inserted:

    document.addEventListener('animationstart', function(event) {
        if (event.animationName == 'widget_inserted') {
            ...
        }
    });
    

    You can view a live demo here