W3docs

Manipulation du DOM en JavaScript

Apprenez à manipuler le DOM en JavaScript : modifier le contenu avec textContent et innerHTML, gérer les attributs et classes, créer, insérer, cloner et supprimer des éléments, avec des exemples pratiques.

La manipulation du DOM (Document Object Model) en JavaScript est une compétence fondamentale pour les développeurs web. Le DOM est une représentation en arbre, dynamique, de la page que le navigateur construit à partir de votre HTML ; le manipuler consiste à utiliser JavaScript pour lire et modifier cet arbre à l'exécution, afin que la page se mette à jour sans rechargement.

Ce guide couvre les quatre opérations les plus courantes :

  • Lire et modifier le contenu avec textContent et innerHTML.
  • Lire et modifier les attributs avec getAttribute, setAttribute et classList.
  • Créer et insérer des éléments avec createElement, append, insertBefore et insertAdjacentHTML.
  • Supprimer et remplacer des éléments avec remove() et replaceWith().

Avant de pouvoir manipuler un élément, vous devez d'abord le trouver. Si vous n'êtes pas encore à l'aise avec getElementById, querySelector et leurs équivalents, lisez d'abord Sélectionner des éléments DOM et Recherche : getElement, querySelector — chaque exemple ci-dessous suppose que vous disposez déjà d'une référence au nœud.

Modifier le contenu et les attributs des éléments

Manipuler le contenu et les attributs des éléments DOM est un aspect crucial du développement web dynamique. En modifiant le contenu, nous pouvons mettre à jour le texte ou le HTML d'un élément. En modifiant les attributs, nous pouvons changer des propriétés comme class, id ou src. JavaScript fournit des méthodes puissantes pour accomplir ces tâches, nous permettant de créer des applications web réactives et interactives. Voyons comment utiliser efficacement innerHTML, textContent, setAttribute et getAttribute.

Modifier le contenu d'un élément

Nous pouvons modifier le contenu d'un élément en utilisant les propriétés innerHTML ou textContent.

innerHTML vs textContent

innerHTML nous permet de définir ou d'obtenir le contenu HTML d'un élément, y compris les balises HTML.

<!DOCTYPE html>
<html>
<head>
    <title>innerHTML vs textContent</title>
    <style>
        .content-container {
            margin: 20px;
            padding: 10px;
            border: 1px solid #ccc;
            border-radius: 5px;
        }
        .html-content {
            color: red;
        }
    </style>
</head>
<body>
    <div class="content-container">
        <p id="content">Original paragraph content.</p>
        <button id="change-innerHTML">Change using innerHTML</button>
        <button id="change-textContent">Change using textContent</button>
    </div>

    <script>
        const content = document.getElementById('content');
        const innerHTMLButton = document.getElementById('change-innerHTML');
        const textContentButton = document.getElementById('change-textContent');

        innerHTMLButton.addEventListener('click', () => {
            content.innerHTML = 'New content with <strong class="html-content">HTML</strong> tags.';
        });

        textContentButton.addEventListener('click', () => {
            content.textContent = 'Updated paragraph content without HTML tags.';
        });
    </script>
</body>
</html>

Explication :

  • innerHTML nous permet de définir ou d'obtenir le contenu HTML d'un élément, y compris les balises HTML. Dans l'exemple, cliquer sur le bouton "Change using innerHTML" remplace le contenu du paragraphe par un nouveau contenu incluant des balises HTML, ce qui modifie l'apparence du texte.
  • textContent définit ou obtient le contenu texte d'un élément sans analyser les balises HTML. Cliquer sur le bouton "Change using textContent" remplace le contenu du paragraphe par du texte brut, en ignorant toute balise HTML.
Info

Utilisez textContent lors de l'insertion de contenu généré par l'utilisateur pour éviter les risques de sécurité tels que les XSS (Cross-Site Scripting). Assigner une chaîne brute provenant d'un utilisateur à innerHTML permet à un attaquant d'injecter des balises <script> ou des attributs de gestionnaire d'événements qui s'exécutent sur votre page. textContent n'analyse jamais le HTML, donc la chaîne est affichée telle quelle et est toujours sûre.

Il existe également une troisième propriété, outerHTML, qui représente l'élément et sa propre balise. L'assigner remplace l'élément entièrement :

// Replace the whole <p> with an <h2>, keeping it in the same position
const p = document.querySelector('p');
p.outerHTML = '<h2>A heading instead</h2>';
// After this, `p` still points at the old, detached node — re-query if you need the new one.

Modifier les attributs d'un élément

Nous pouvons modifier les attributs d'un élément à l'aide de la méthode setAttribute et les récupérer avec la méthode getAttribute. Ces méthodes sont utiles pour modifier dynamiquement des éléments en fonction des interactions utilisateur ou d'autres événements.

<!DOCTYPE html>
<html>
<head>
    <title>setAttribute and getAttribute</title>
</head>
<body>
    <div id="container" class="initial-class">Container content</div>
    <button id="change-attribute">Change Attribute</button>
    <button id="get-attribute">Get Attribute</button>

    <script>
        const container = document.getElementById('container');
        const changeAttributeButton = document.getElementById('change-attribute');
        const getAttributeButton = document.getElementById('get-attribute');

        changeAttributeButton.addEventListener('click', () => {
            container.setAttribute('class', 'new-class');
            alert('Class attribute changed to "new-class"');
        });

        getAttributeButton.addEventListener('click', () => {
            const className = container.getAttribute('class');
            alert(`Current class attribute: ${className}`);
        });
    </script>
</body>
</html>

Explication :

  • setAttribute('attributeName', 'value') : cette méthode nous permet de définir une nouvelle valeur pour un attribut spécifié d'un élément. Dans l'exemple, cliquer sur le bouton "Change Attribute" change l'attribut class du <div> de "initial-class" à "new-class".
  • getAttribute('attributeName') : cette méthode récupère la valeur actuelle de l'attribut spécifié. Cliquer sur le bouton "Get Attribute" affiche une alerte avec la valeur actuelle de l'attribut class du <div>.
Info

Utilisez toujours setAttribute et getAttribute pour les attributs personnalisés et les attributs générés dynamiquement. Pour la manipulation des classes, préférez l'API classList ci-dessous — elle modifie les classes individuellement au lieu d'écraser toute la chaîne class.

Attributs vs propriétés

Une source de confusion fréquente : un attribut HTML (ce qui est écrit dans le balisage) n'est pas toujours identique à la propriété DOM (la valeur dynamique sur l'objet JavaScript). getAttribute('value') lit la valeur d'origine dans le balisage, tandis que input.value lit ce que l'utilisateur a actuellement saisi. Pour les attributs boolean, la différence est encore plus marquée — checkbox.getAttribute('checked') reflète le balisage, tandis que checkbox.checked reflète l'état courant. En règle générale : utilisez les propriétés (el.id, el.value, el.checked) pour les valeurs standard qui changent fréquemment, et setAttribute/getAttribute pour les attributs data- personnalisés ou les attributs de balisage ponctuels.

Pour lire et écrire des attributs data-*, il existe une API dédiée et ergonomique — la propriété dataset :

// <div id="card" data-user-id="42" data-role="admin"></div>
const card = document.getElementById('card');
console.log(card.dataset.userId); // "42" (note: data-user-id → userId)
card.dataset.role = 'editor';     // writes data-role="editor"

Gérer les classes avec classList

classList permet d'activer ou de désactiver des classes individuelles sans affecter les autres classes déjà présentes :

element.classList.add('new-class');       // add one (or several) classes
element.classList.remove('old-class');    // remove a class
element.classList.toggle('active');       // add if absent, remove if present
element.classList.replace('open', 'shut'); // swap one class for another
console.log(element.classList.contains('active')); // true / false

toggle accepte un deuxième argument optionnel pour forcer un état, ce qui est pratique pour synchroniser une classe avec une condition : el.classList.toggle('valid', isValid). Pour un travail de style plus approfondi — notamment la lecture et l'écriture de la propriété style — consultez Travailler avec les styles dans le DOM.

Ajouter et supprimer des éléments

Nous pouvons ajouter de nouveaux éléments au DOM ou supprimer des éléments existants.

Ajouter des éléments

Pour ajouter de nouveaux éléments au DOM, nous les créons d'abord à l'aide de la méthode createElement, puis nous les ajoutons à un élément existant avec appendChild ou nous les insérons à une position spécifique avec insertBefore.

createElement(), appendChild(), insertBefore()

<!DOCTYPE html>
<html>
<head>
    <title>Adding Elements</title>
</head>
<body>
    <div id="task-list">
        <h2>Task List</h2>
        <ul id="tasks">
            <li>Initial task</li>
        </ul>
        <input type="text" id="new-task" placeholder="New task">
        <button id="add-task">Add Task</button>
        <button id="insert-before">Insert Before First Task</button>
    </div>

    <script>
        const taskList = document.getElementById('tasks');
        const newTaskInput = document.getElementById('new-task');
        const addTaskButton = document.getElementById('add-task');
        const insertBeforeButton = document.getElementById('insert-before');

        addTaskButton.addEventListener('click', () => {
            const newTaskText = newTaskInput.value;
            if (newTaskText.trim()) {
                const newTask = document.createElement('li');
                newTask.textContent = newTaskText;
                taskList.appendChild(newTask);
                newTaskInput.value = '';
            }
        });

        insertBeforeButton.addEventListener('click', () => {
            const newTaskText = newTaskInput.value;
            if (newTaskText.trim()) {
                const newTask = document.createElement('li');
                newTask.textContent = newTaskText;
                const firstTask = taskList.firstElementChild;
                taskList.insertBefore(newTask, firstTask);
            }
        });
    </script>
</body>
</html>

Explication :

  • createElement('tagName') : cette méthode crée un nouvel élément spécifié par tagName. Par exemple, document.createElement('li') crée un nouvel élément <li>.
  • appendChild(newElement) : cette méthode ajoute un nouvel élément enfant à un élément parent spécifié. Dans l'exemple, cliquer sur le bouton "Add Task" crée un nouvel élément de liste (<li>) et l'ajoute à la liste des tâches (<ul>).
  • insertBefore(newElement, referenceElement) : cette méthode insère un nouvel élément avant un élément de référence spécifié au sein du même parent. Cliquer sur le bouton "Insert Before First Task" crée un nouvel élément de liste (<li>) et l'insère avant la première tâche de la liste.
Note

Pour insérer des chaînes HTML directement, utilisez insertAdjacentHTML(). Pour remplacer un élément existant, element.replaceWith(newElement) est une alternative moderne à la combinaison de remove() et appendChild().

insertAdjacentHTML et les méthodes d'insertion modernes

Lorsque vous disposez déjà d'une chaîne HTML (plutôt que d'un nœud construit avec createElement), insertAdjacentHTML(position, html) l'analyse et l'insère en un seul appel. L'argument position est l'un des quatre mots-clés relatifs à l'élément :

// Given:  <div id="box">content</div>
const box = document.getElementById('box');
box.insertAdjacentHTML('beforebegin', '<p>before the box</p>'); // before <div>
box.insertAdjacentHTML('afterbegin',  '<p>first child</p>');     // inside, at the start
box.insertAdjacentHTML('beforeend',   '<p>last child</p>');      // inside, at the end
box.insertAdjacentHTML('afterend',    '<p>after the box</p>');   // after </div>

Les navigateurs modernes fournissent également append(), prepend(), before() et after(), qui acceptent des nœuds ou des chaînes simples et peuvent prendre plusieurs arguments à la fois — ils sont généralement plus clairs que appendChild/insertBefore :

const list = document.getElementById('tasks');
const item = document.createElement('li');
item.textContent = 'New task';
list.append(item, 'some trailing text'); // append node + string together
list.prepend('Top of the list');         // insert at the start

Cloner des éléments

Pour dupliquer un nœud existant au lieu d'en construire un de zéro, utilisez cloneNode(deep). Passez true pour copier l'élément avec tous ses descendants ; passez false (ou rien) pour copier uniquement l'élément lui-même :

const template = document.getElementById('card');
const copy = template.cloneNode(true); // deep clone, including children
copy.id = 'card-2';                    // ids must stay unique
document.body.append(copy);

Pour des balises complexes répétées, l'élément <template> est l'outil conçu à cet effet — son contenu est inerte jusqu'à ce que vous le cloniez.

Supprimer des éléments

Pour supprimer un élément, nous pouvons utiliser la méthode moderne element.remove().

<!DOCTYPE html>
<html>
<head>
    <title>Removing Elements</title>
</head>
<body>
    <div id="container">
        <p id="paragraph">This is a paragraph.</p>
        <button id="remove-paragraph">Remove Paragraph</button>
    </div>

    <script>
        const container = document.getElementById('container');
        const paragraph = document.getElementById('paragraph');
        const removeParagraphButton = document.getElementById('remove-paragraph');

        removeParagraphButton.addEventListener('click', () => {
            paragraph.remove();
        });
    </script>
</body>
</html>

Explication :

  • element.remove() : cette méthode moderne supprime directement un élément spécifié du DOM. Dans l'exemple, cliquer sur le bouton "Remove Paragraph" supprime l'élément <p> de la page.
Info

L'utilisation de element.remove() est l'approche recommandée pour les modifications de contenu dynamique, comme la suppression d'articles d'un panier d'achat, car elle offre une syntaxe plus propre que la méthode héritée parent.removeChild(child) (qui reste utile lorsque vous avez besoin d'une référence au nœud supprimé).

Insérer de nombreux éléments efficacement

Chaque fois que vous insérez un nœud dans le document actif, le navigateur peut devoir recalculer la mise en page et repeindre. Faire cela dans une boucle — une fois par élément — est inefficace. Un DocumentFragment vous permet d'assembler des nœuds hors écran et de les insérer tous en une seule opération :

const list = document.getElementById('tasks');
const fragment = document.createDocumentFragment();

for (let i = 1; i <= 1000; i++) {
  const li = document.createElement('li');
  li.textContent = `Task ${i}`;
  fragment.appendChild(li); // no layout work — fragment is not in the document
}

list.appendChild(fragment); // one insertion, one reflow

Deux règles de base permettent de garder un code DOM-lourd performant : regroupez vos lectures et écritures (n'entremêlez pas la lecture de offsetHeight avec la définition de styles, sous peine de forcer des recalculs répétés), et préférez construire une chaîne et assigner innerHTML une seule fois plutôt que de nombreux petits appels appendChild lorsque vous n'attachez pas de gestionnaires d'événements à chaque nœud. Pour un traitement approfondi, consultez Optimisation des performances du DOM.

Exemple : liste de tâches dynamique

Créons une simple application de liste de tâches pour illustrer les concepts ci-dessus.

<!DOCTYPE html>
<html>
<head>
    <title>To-Do List</title>
</head>
<body>
    <div id="todo-list">
        <h2>My To-Do List</h2>
        <ul id="tasks">
            <li>Learn JavaScript</li>
        </ul>
        <input type="text" id="new-task" placeholder="New task">
        <button id="add-task">Add Task</button>
    </div>

    <script>
        const taskList = document.getElementById('tasks');
        const newTaskInput = document.getElementById('new-task');
        const addTaskButton = document.getElementById('add-task');

        addTaskButton.addEventListener('click', () => {
            const newTaskText = newTaskInput.value;
            if (newTaskText.trim()) {
                const newTask = document.createElement('li');
                newTask.textContent = newTaskText;
                taskList.appendChild(newTask);
                newTaskInput.value = '';
            }
        });

        taskList.addEventListener('click', (event) => {
            if (event.target.tagName === 'LI') {
                event.target.remove();
            }
        });
    </script>
</body>
</html>

Explication :

  • createElement crée un nouvel élément de liste pour la tâche, et appendChild l'ajoute à la liste.
  • Un seul écouteur de clic est attaché au <ul>, et non à chaque <li>. Comme les clics remontent de l'élément cliqué vers ses ancêtres, l'écouteur inspecte event.target pour déterminer quelle tâche a été cliquée et la supprime. Ce modèle est appelé délégation d'événements, et c'est la raison pour laquelle le gestionnaire continue de fonctionner pour les tâches qui n'existaient pas au chargement de la page.
Note

La délégation d'événements est la raison pour laquelle nous n'ajoutons pas un écouteur séparé à chaque fois qu'une tâche est créée — un seul écouteur sur le parent gère les enfants actuels et futurs. Pour approfondir la propagation, event.target vs event.currentTarget, et la délégation, lisez Gestion des événements dans le DOM.

Info

Lorsqu'une interface comporte de nombreux éléments d'état indépendants et fréquemment mis à jour, maintenir manuellement la synchronisation du DOM devient source d'erreurs. Des frameworks tels que React, Vue ou Svelte vous permettent de décrire à quoi doit ressembler l'interface pour un état donné et gèrent les mises à jour du DOM pour vous. Les techniques manuelles décrites dans ce chapitre constituent la fondation sur laquelle ces frameworks sont construits.

Conclusion

Maîtriser la manipulation du DOM est essentiel pour créer des applications web dynamiques et interactives. Vous savez maintenant comment modifier le contenu (textContent, innerHTML, outerHTML), travailler avec les attributs et les classes (setAttribute, dataset, classList), créer et insérer des nœuds (createElement, append, insertAdjacentHTML, cloneNode), les supprimer et les remplacer (remove(), replaceWith()), et regrouper les insertions efficacement avec un DocumentFragment.

Pour continuer à construire sur ces bases :

Pratique

Pratique
Laquelle des méthodes suivantes peut être utilisée pour modifier le contenu d'un élément DOM ?
Laquelle des méthodes suivantes peut être utilisée pour modifier le contenu d'un élément DOM ?
Pratique
Vous devez afficher en toute sécurité un commentaire saisi par un utilisateur dans un paragraphe. À quelle propriété devez-vous l'assigner ?
Vous devez afficher en toute sécurité un commentaire saisi par un utilisateur dans un paragraphe. À quelle propriété devez-vous l'assigner ?
Pratique
Quel est le principal avantage d'insérer de nombreux nouveaux éléments via un DocumentFragment ?
Quel est le principal avantage d'insérer de nombreux nouveaux éléments via un DocumentFragment ?
Was this page helpful?