Manipolare il Document Object Model (DOM) è il pane quotidiano di ogni sviluppatore frontend. Capire a fondo come e quando usare innerText e innerHTML fa la differenza tra codice sicuro, performante e facilmente manutenibile, e codice che apre la porta a bug, rallentamenti o – peggio – vulnerabilità XSS.
Introduzione
Quando interagisci con il DOM, spesso hai bisogno di leggere o modificare il contenuto di un elemento. Questo è il cuore della manipolazione lato client in JavaScript: poter leggere, aggiornare e trasformare dinamicamente ogni nodo della pagina in base alle azioni dell’utente.
Per chi parte da zero, leggi il nostro articolo su Cos’è il DOM e come manipolarlo in JavaScript per una panoramica completa.
In questo articolo analizziamo:
- Che cosa sono innerText e innerHTML.
- Le differenze tecniche e pratiche.
- Come evitare problemi di sicurezza e di performance.
- Best practice moderne.
- FAQ sugli errori più comuni.
Cosa sono innerText e innerHTML
innerText
innerText
restituisce o imposta solo il testo reso visibile all’utente, rispettando CSS e layout (ad esempio display:none
, visibility:hidden
, text-transform
, white-space
, ecc.). In pratica si comporta come se copiassi e incollassi il testo così come lo vedi sullo schermo.
<p id="demo">Hello <span style="display:none">Secret</span> World</p>
<script>
const p = document.getElementById("demo");
console.log(p.innerText); // "Hello World" (niente "Secret")
</script>
Pro: semplice, evita di incollare markup indesiderato.
Contro: forza il reflow perché deve calcolare lo stile corrente per sapere cosa è visibile; non è standardizzato in modo uniforme tra tutti i browser; non conserva spazi multipli o tag <br>
.
innerHTML
innerHTML
restituisce o imposta l’intero markup HTML contenuto nell’elemento.
console.log(p.innerHTML); // "Hello <span style=\"display:none\">Secret</span> World"
Pro: flessibile, permette di inserire intere strutture di markup in un colpo solo.
Contro: se usato con input dell’utente può aprire falle XSS; ogni volta che lo imposti, il browser distrugge e ricostruisce il sotto‑albero DOM con costi di performance maggiori rispetto a innerText
o textContent
.
Differenze principali
1. Sicurezza (XSS)
- innerText (e l’alternativa moderna
textContent
) inserisce solo testo. Qualunque stringa HTML viene automaticamente espressa come testo letterale, quindi è intrinsecamente più sicura. - innerHTML interpreta la stringa come HTML. Se inserisci
element.innerHTML = `Ciao ${utente}`;
eutente
contiene<img src=x onerror=alert('XSS')>
, stai regalando un’esecuzione di JavaScript non voluta. - Mitigazione: valida o sanifica con librerie come DOMPurify, oppure usa API createElement/append.
2. Performance
- innerText calcola gli stili computati → reflow → potenziale repaint. Su grandi chunk di DOM o in loop stretto può incidere.
- innerHTML effettua parsing HTML + nuova creazione dei nodi. Cicli che aggiornano frequentemente
innerHTML
(es. building list via concatenazione di stringhe) sono notoriamente lenti e causano layout thrashing. - Best practice: nei loop massivi costruisci nodi con
createElement
, frammenti (DocumentFragment
) o templating (es. lit‑html), poi inserisci una sola volta.
3. Rendering di spazi e formattazione
innerText
collassa gli spazi e ignora i tag di formattazione (eccetto\n
convertiti in<br>
sewhite-space
lo consente).innerHTML
preserva tag, commenti e spazi (a meno di normalizzazione del parser HTML).
Quando usare innerText e quando innerHTML
Caso d’uso | innerText | innerHTML |
---|---|---|
Mostrare testo da user input | ✅ (sicuro) | ❌ (richiede sanitizzazione) |
Stampare markup statico definito in codice | ❌ (perderesti il markup) | ✅ |
Aggiornamenti frequenti in ciclo | ⚠️ (reflow) | ⚠️ (ricrea sotto‑DOM) |
Estrarre solo il testo visibile | ✅ | ❌ |
Effetti di formattazione HTML complessa | ❌ | ✅ |
Regola d’oro: se hai bisogno solo di testo, usa textContent
(o innerText
quando ti serve rispettare CSS). Se devi iniettare markup, preferisci API DOM o sanitizza prima di usare innerHTML
.
Esempi di codice pratici
Esempio 1 – Toggle di un bottone
<button id="btn">Mostra dettagli</button>
<p id="details" hidden>Questi sono i dettagli 📄</p>
<script>
const btn = document.getElementById("btn");
const details = document.getElementById("details");
btn.addEventListener("click", () => {
const isHidden = details.hasAttribute("hidden");
details.toggleAttribute("hidden");
btn.innerText = isHidden ? "Nascondi dettagli" : "Mostra dettagli";
});
</script>
Esempio 2 – Costruire una lista ‑ modo slow (innerHTML)
const ul = document.querySelector("ul");
let html = "";
items.forEach(item => {
html += `<li>${item}</li>`; // ❌ parsing multiplo
});
ul.innerHTML = html;
Esempio 3 – Costruire una lista ‑ modo fast (DOM API)
const ul = document.querySelector("ul");
const frag = document.createDocumentFragment();
items.forEach(item => {
const li = document.createElement("li");
li.textContent = item;
frag.appendChild(li);
});
ul.appendChild(frag); // singolo reflow
Best practices moderne nella manipolazione DOM
- Preferisci
textContent
ainnerText
quando non ti serve la formattazione visibile. - Sanitizza SEMPRE l’input prima di usare
innerHTML
(DOMPurify, html‑escaper, librerie templating safe‑by‑default). - Batch DOM updates: usa
DocumentFragment
, richiestarequestAnimationFrame
, o framework/librerie che diffano (React, Vue, SolidJS). - Evita concatenazioni di stringhe lunghe in loop; il browser re‑parsea l’HTML ad ogni iterazione.
- Valuta Shadow DOM o Web Components per isolare stile e markup.
- Misura con strumenti come Performance tab (Chrome DevTools) o Lighthouse: ogni DOM write massiva va profilata.
FAQ rapide
“Perché il mio innerHTML
non funziona?”
Spesso l’errore è tentare di usare innerHTML
su elementi self‑closing (<input>
), oppure il markup risultante non è valido (es. tag aperti/non chiusi). Controlla con il validator.
“Posso usare innerText
per elementi complessi?”
Sì, ma perderai tutti i tag e gli spazi multipli. Se vuoi estrarre il testo e mantenere la semantica, usa textContent
+ parsing successivo.
“innerText
è standard?”
Non ufficialmente nello standard WHATWG, ma de‑facto supportato dai principali browser. Per consistenza e performance, preferisci textContent
.
“Qual è la differenza con outerHTML
?”outerHTML
include anche il nodo corrente oltre al suo contenuto. Sovrascriverlo ricrea l’intero nodo.
Conclusione
La scelta tra innerText e innerHTML impatta sicurezza, performance e mantenibilità della tua app. Usa quello giusto al momento giusto e il tuo DOM ti ringrazierà.
Hai trovato utile questa guida? Approfondisci la gestione degli eventi DOM con il nostro articolo dedicato a addEventListener – scopri pattern avanzati come delegation e once handlers!