Ressources pour développeur web

Théme de la semaine : Snippets utiles

MutationObserver : Détecter changements du DOM en JavaScript

Temps de lecture estimé : 7 minutes
Accueil Javascript MutationObserver : Détecter changements du DOM en JavaScript

Vous avez sûrement déjà vécu cette situation : une partie de votre page change mais votre JavaScript ne le remarque pas. Un élément est ajouté, supprimé ou modifié dans le DOM, et pourtant votre script ne détecte rien. Il existe une solution propre, moderne et très puissante pour surveiller en temps réel les changements du DOM : MutationObserver.

  • Repérer automatiquement une modification du DOM sans bricolage ni boucle inefficace
  • Rendre vos interfaces dynamiques plus intelligentes en réagissant en temps réel aux changements du DOM
  • Gagner en performance et en propreté de code en maîtrisant une méthode moderne et fiable adaptée aux projets réels

Dans ce tutoriel, vous allez découvrir comment détecter une modification DOM en JavaScript, comprendre les concepts derrière, et surtout les utiliser concrètement dans vos projets.

Comprendre le DOM

Avant de parler de changement DOM, il faut bien comprendre ce qu’est le DOM.

Le DOM (Document Object Model) est une représentation de votre page HTML sous forme d’arbre. Chaque balise devient un “nœud” :

<div id="app">
    <p>Bonjour</p>
</div>

Votre JavaScript peut lire, modifier, ajouter ou supprimer ces éléments. Et c’est là que tout devient intéressant.

👉 Pour ceux qui débutent : Comprendre le DOM en JS

Pourquoi détecter un changement du DOM ?

Imaginez plusieurs cas concrets :

  • Vous utilisez un script externe qui modifie votre page
  • Vous avez une interface dynamique (AJAX, React, Vue…)
  • Vous voulez déclencher une action dès qu’un élément apparaît

Exemple typique :

“Dès qu’un bouton est ajouté dans la page, je veux lui ajouter un événement click.”

Sans détection de modification DOM, vous devriez vérifier en boucle… ce qui est une très mauvaise idée (et votre CPU va pleurer). Heureusement, il existe une méthode bien plus élégante.

L’ancienne méthode (à éviter) : setInterval

Avant, certains développeurs faisaient ça :

setInterval(() => {
    const element = document.querySelector('.nouveau');
    if (element) {
        console.log('Element détecté !');
    }
}, 1000);

Ça fonctionne… mais :

  • c’est lent
  • ça consomme des ressources inutilement
  • ce n’est pas précis

Bref, c’est un peu comme vérifier toutes les minutes si quelqu’un a sonné à votre porte, au lieu d’avoir une sonnette.

La vraie solution : MutationObserver

Bienvenue dans le cœur du sujet.

MutationObserver est une API JavaScript qui permet de détecter automatiquement les changements du DOM.

  • C’est propre, performant, et surtout fait pour ça.

Premier exemple simple de MutationObserver

On va commencer très doucement :

<div id="container"></div>
<button id="add">Ajouter un élément</button>

Puis, en JavaScript :

const container = document.getElementById('container');

const observer = new MutationObserver((mutations) => {
    console.log('Changement détecté dans le DOM !');
    console.log(mutations);
});

observer.observe(container, {
    childList: true
});

Maintenant, on va ajouter un élément :

document.getElementById('add').addEventListener('click', () => {
    const p = document.createElement('p');
    p.textContent = "Nouvel élément";
    container.appendChild(p);
});

Prenons le temps de bien comprendre.

  • MutationObserver écoute les changements
  • La fonction reçoit un tableau mutations
  • observe() démarre l’écoute

Et ici :

childList: true

signifie :

“Je veux détecter les ajouts ou suppressions d’enfants dans le DOM”

Comprendre les types de modification DOM

Quand on parle de changement DOM, il y a plusieurs types de modifications possibles.

1. Ajout ou suppression d’éléments

C’est le cas le plus courant.

childList: true

2. Modification d’attributs

Par exemple :

<div id="box" class="red"></div>

Si vous changez la classe :

box.classList.add('active');

Pour détecter ça :

observer.observe(box, {
    attributes: true
});

3. Modification du contenu texte

Prenons comme exemple :

box.textContent = "Nouveau texte";

À surveiller avec :

observer.observe(box, {
    characterData: true,
    subtree: true
});

Exemple concret : détecter un changement de classe

Le code HTML :

<div id="box">Test</div>
<button id="change">Changer classe</button>

Puis, en JavaScript :

const box = document.getElementById('box');

const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
if (mutation.type === 'attributes') {
console.log('Attribut modifié !');
console.log('Nouvelle classe :', box.className);
}
});
});

observer.observe(box, {
attributes: true
});

document.getElementById('change').addEventListener('click', () => {
box.classList.toggle('active');
});

À chaque modification DOM sur les attributs :

  • MutationObserver capte le changement et vous pouvez réagir immédiatement

C’est ultra puissant.

Observer tout un sous-arbre du DOM

Très souvent, vous ne voulez pas surveiller un seul élément, mais toute une zone.

C’est là que subtree entre en jeu.

observer.observe(container, {
    childList: true,
    subtree: true
});

Cela signifie :

“Observe tous les changements dans cet élément ET tous ses enfants.”

Exemple pratique : détecter un élément injecté dynamiquement

Imaginez un script externe qui ajoute un bouton.

setTimeout(() => {
    const btn = document.createElement('button');
    btn.textContent = "Cliquez-moi";
    document.body.appendChild(btn);
}, 2000);

Vous voulez détecter ce bouton automatiquement.

const observer = new MutationObserver((mutations) => {
    mutations.forEach((mutation) => {
        mutation.addedNodes.forEach((node) => {
            if (node.tagName === 'BUTTON') {
                console.log('Bouton ajouté !');
            }
        });
    });
});

observer.observe(document.body, {
    childList: true,
    subtree: true
});

Pourquoi c’est formidable ?

Parce que :

  • vous n’avez pas besoin de savoir quand l’élément arrive
  • votre code reste réactif
  • c’est parfaitement adapté aux interfaces modernes

Comment arrêter l’observation

Un observer actif en permanence peut être inutile. Mais vous avez aussi la possibilité de le stopper.

Pour l’arrêter :

observer.disconnect();

Très utile si :

  • vous avez déjà détecté ce que vous vouliez
  • vous changez de page (SPA)
  • vous voulez optimiser les performances

Erreur fréquente de débutant

Attention à ceci :

  • MutationObserver peut déclencher plusieurs mutations pour une seule action.

Donc évitez de faire :

Formation web et informatique - Alban Guillier - Formateur

Des formations informatique pour tous !

Débutant ou curieux ? Apprenez le développement web, le référencement, le webmarketing, la bureautique, à maîtriser vos appareils Apple et bien plus encore…

Formateur indépendant, professionnel du web depuis 2006, je vous accompagne pas à pas et en cours particulier, que vous soyez débutant ou que vous souhaitiez progresser. En visio, à votre rythme, et toujours avec pédagogie.

Découvrez mes formations Qui suis-je ?
console.log('changement');

sans filtrer.

Préférez analyser :

mutation.type
mutation.addedNodes
mutation.attributeName

Sinon, vous allez vite vous retrouver avec des logs dans tous les sens.

Cas concret

Sur un site web, vous pourriez avoir besoin de :

  • détecter automatiquement des nouveaux éléménts
  • recalculer un résultat dès modification DOM
  • analyser les nouveautés en temps réel

Exemple :

if (node.tagName === 'A') {
    console.log('Nouveau lien détecté :', node.href);
}

Aller plus loin : exploiter pleinement les changements du DOM

Vous avez maintenant compris comment détecter un changement DOM avec MutationObserver. Mais soyons honnêtes : dans un vrai projet, ce n’est jamais aussi simple.

Les pages deviennent complexes, les modifications DOM sont nombreuses, et si vous ne structurez pas bien votre logique… c’est vite le chaos.

Filtrer intelligemment les mutations

Quand un changement du DOM se produit, vous recevez souvent beaucoup d’informations. Trop, parfois.

  • Si vous traitez tout sans réfléchir, votre script risque de devenir lent ou imprécis.
const observer = new MutationObserver((mutations) => {
    console.log(mutations);
});

Cela affiche tout… mais ça ne sert pas à grand-chose. Une bonne pratique serait de filtrer les mutations utiles.

Prenons un cas concret :

Vous voulez détecter uniquement les nouveaux liens (<a>)

const observer = new MutationObserver((mutations) => {
    mutations.forEach((mutation) => {

        if (mutation.type === 'childList') {

            mutation.addedNodes.forEach((node) => {

                if (node.nodeType === 1 && node.tagName === 'A') {
                    console.log('Lien détecté :', node.href);
                }

            });

        }

    });
});

observer.observe(document.body, {
    childList: true,
    subtree: true
});

Maintenant, vous avez :

  • ciblé uniquement les ajouts (childList)
  • ignoré le bruit inutile
  • filtré les vrais éléments HTML (nodeType === 1)
  • ciblé un type précis (A)

C’est exactement comme ça qu’on travaille proprement.

Optimiser les performances

Un MutationObserver, c’est puissant… mais mal utilisé, ça peut ralentir votre site. Un peu comme un stagiaire hyper motivé qui regarde absolument tout, tout le temps.

Commencer par limiter la zone observée, il faut donc évitez ceci :

observer.observe(document.body, {
    subtree: true
});

Mieux vaut :

observer.observe(document.getElementById('app'), {
    subtree: true
});

Ainsi vous réduisez le nombre de modifications DOM à analyser.

Veillez à ne surveiller que ce qui est nécessaire. Inutile de tout activer :

attributes: true,
childList: true,
characterData: true

Si vous avez juste besoin des ajouts :

childList: true

Simple, efficace.

Débouncer les actions

Si beaucoup de changements DOM arrivent en même temps, votre fonction peut être appelée en boucle. La meilleure solution : temporiser.

let timeout;

const observer = new MutationObserver(() => {

clearTimeout(timeout);

timeout = setTimeout(() => {
console.log('Traitement après stabilisation du DOM');
}, 200);

});

Cela permet d’attendre que le DOM “se calme” avant d’agir. C’est comme attendre que tout le monde ait fini de parler avant de répondre.

Cas concret : ajouter automatiquement un événement

Imaginez :

Vous voulez que chaque bouton ajouté dynamiquement ait un événement click.

const observer = new MutationObserver((mutations) => {

mutations.forEach((mutation) => {

mutation.addedNodes.forEach((node) => {

if (node.nodeType === 1 && node.tagName === 'BUTTON') {

node.addEventListener('click', () => {
alert('Bouton cliqué !');
});

}

});

});

});

observer.observe(document.body, {
childList: true,
subtree: true
});

Même les boutons ajoutés après coup fonctionnent immédiatement. Et ça, pour une interface dynamique, c’est de l’or.

Cas avancé : surveiller un attribut précis

Vous pouvez aller encore plus loin.

Exemple :

Vous voulez détecter uniquement les changements de classe.

observer.observe(element, {
    attributes: true,
    attributeFilter: ['class']
});

Pourquoi utiliser attributeFilter ?

Parce que sinon, vous écoutez TOUS les attributs :

  • id
  • style
  • data-*
  • etc.

Et encore une fois… du bruit inutile.

Les erreurs fréquentes et comment les éviter

Voici les pièges classiques.

1. Observer trop large

Résultat : performances mauvaises.

👉 Solution : cibler un conteneur précis

2. Ne pas filtrer

Résultat : logs inutiles, bugs

👉 Solution : analyser mutation.type

3. Oublier disconnect()

Résultat : fuite de performance

👉 Solution :

observer.disconnect();

4. Ne pas vérifier nodeType

Résultat : erreurs avec des nœuds texte

👉 Toujours faire :

if (node.nodeType === 1)

Une analogie simple pour tout retenir

Imaginez que le DOM est une maison.

  • MutationObserver = une caméra de surveillance
  • observe() = vous choisissez les pièces à surveiller
  • mutations = les événements détectés

Et vous pouvez décider :

  • d’ignorer certains mouvements
  • de déclencher une alarme
  • ou de ne rien faire

Vous venez de découvrir un outil extrêmement puissant : la détection de changement du DOM en JavaScript.

Et ce n’est pas juste un “truc technique”. C’est un véritable atout pour rendre vos interfaces intelligentes, réactives et modernes.

Ce qu’il faut vraiment retenir, ce n’est pas seulement comment utiliser MutationObserver, mais pourquoi vous l’utilisez. Derrière chaque modification DOM, il y a une opportunité : automatiser, analyser, améliorer.