Afficher un nom, un prix, un message d'erreur : une large part du travail d'une interface consiste à remplacer du texte dans une page déjà affichée. Le DOM propose trois propriétés pour cela, et elles ne font pas du tout la même chose.
La plus sûre des trois est aussi la plus simple. Elle ne connaît que du texte, et c'est précisément ce qui la rend recommandable par défaut.
Définition
textContent est une propriété disponible sur tout nœud du DOM. En lecture, elle rend la concaténation du texte contenu dans l'élément et dans tous ses descendants, balises retirées. En écriture, elle remplace la totalité du contenu de l'élément par une seule chaîne de caractères.
const titre = document.querySelector("h1");
console.log(titre.textContent); // "Bonjour Camille"
titre.textContent = "Bonjour Alex";
// le h1 contient désormais un seul nœud de texteLa valeur lue est toujours une String (chaîne de caractères). Un élément vide rend une chaîne vide, jamais null, ce qui évite d'avoir à tester l'absence avant de manipuler le résultat.
Trois propriétés, trois résultats
Sur un même élément, les trois propriétés de lecture du contenu donnent trois valeurs différentes. Le tableau les compare sur trois colonnes : la propriété, ce qu'elle rend, et ce qu'elle coûte.
| Propriété | Ce qu'elle rend en lecture | Ce qu'il faut savoir |
|---|---|---|
textContent | Tout le texte, y compris celui d'un élément masqué en CSS | La plus rapide des trois |
innerText | Le texte tel qu'il s'affiche à l'écran | Oblige le navigateur à recalculer la mise en page |
innerHTML | Le balisage complet, balises comprises | Interprète le HTML quand on écrit dedans |
La troisième ligne explique à elle seule pourquoi innerHTML demande de la prudence : ce qu'on lui donne devient de la structure, pas du texte.
Écrire sans interpréter le HTML
La différence devient une question de sécurité dès que la chaîne vient d'ailleurs : un champ de formulaire, une réponse d'API, un paramètre d'URL.
const zone = document.getElementById("message");
const saisie = '<img src=x onerror="alert(1)">';
zone.textContent = saisie;
// affiche les caractères tels quels, rien ne s'exécute
zone.innerHTML = saisie;
// le navigateur construit une image et déclenche le code attachéAucune fonction d'échappement n'est nécessaire dans le premier cas : la propriété ne construit jamais de balise, quoi qu'on lui passe.
Écrire dans textContent détruit tous les nœuds enfants existants. Si l'élément contenait des boutons avec des écouteurs posés par addEventListener(), ces écouteurs disparaissent avec eux.
Questions fréquentes
textContent ou innerText, lequel choisir ?
textContent par défaut : il est plus rapide et son résultat ne dépend pas du CSS appliqué. innerText ne se justifie que pour obtenir le texte visible, celui qu'un visiteur copierait à la souris, avec les éléments masqués écartés et les retours à la ligne du rendu. Ce confort se paie par un recalcul de la mise en page à chaque lecture.
Comment ajouter du texte sans effacer le reste ?
Une affectation remplace tout, donc concaténer sur la valeur existante fonctionne mais reconstruit inutilement le contenu. La méthode insertAdjacentText ajoute une chaîne à une position précise, et createElement() permet d'ajouter un vrai nœud à côté des autres. Les deux laissent intact ce qui était déjà en place.
Pourquoi ma lecture contient-elle des espaces et des retours à la ligne ?
Parce que l'indentation du fichier HTML est du texte, elle aussi. Un élément écrit sur trois lignes contient des nœuds de texte faits d'espaces, et la propriété les rend fidèlement. Un simple trim() sur la valeur lue règle le cas dans la quasi-totalité des situations.