Il DOM, acronimo di Document Object Model, è il modello attraverso cui un documento HTML o XML viene rappresentato come una struttura di oggetti e nodi che un programma può leggere e modificare.
Nel browser è il livello che permette, per esempio, a JavaScript di trovare un pulsante, cambiare il testo di un paragrafo, aggiungere una classe CSS, creare un nuovo elemento o reagire a un clic.
La distinzione più utile da capire subito è questa: HTML, DOM e JavaScript non sono la stessa cosa. HTML descrive inizialmente struttura e significato del documento; il browser interpreta quel markup e costruisce il DOM; JavaScript può poi utilizzare le interfacce messe a disposizione dal browser per interrogare e modificare quella struttura.
È proprio questo passaggio — dal codice HTML scritto nel file al documento vivo con cui browser e script lavorano — che rende il DOM molto più importante di quanto suggerisca una semplice definizione.
Cos’è il DOM (Document Object Model)
Il DOM è una rappresentazione programmabile di un documento strutturato. La specifica DOM mantenuta da WHATWG lo descrive come il modello utilizzato, tra le altre cose, per gli alberi di nodi e gli eventi.
Quando un browser elabora una pagina HTML, quindi, non conserva semplicemente il sorgente come una lunga stringa di testo. Costruisce una struttura in cui documento, elementi, testo e altri tipi di nodo hanno relazioni precise.
Un markup come questo:
<main> <h1>Guida al DOM</h1> <p>Un primo esempio.</p> </main>
può essere immaginato, in forma molto semplificata, così:
Document
└── html
└── body
└── main
├── h1
│ └── "Guida al DOM"
└── p
└── "Un primo esempio."
Non stiamo più guardando soltanto tag scritti in un file: stiamo osservando oggetti organizzati in una gerarchia.
Cosa significa DOM
DOM significa Document Object Model, cioè modello a oggetti del documento.
Le tre parole descrivono abbastanza bene il concetto:
- Document: la risorsa strutturata con cui stiamo lavorando;
- Object: le diverse parti vengono esposte attraverso oggetti e interfacce programmabili;
- Model: viene fornita una rappresentazione strutturata delle relazioni presenti nel documento.
L’espressione “modello a oggetti” non significa che il browser trasformi banalmente ogni tag in una variabile JavaScript. Significa che espone un modello coerente attraverso interfacce come Document, Element, Node ed EventTarget.
Il DOM è un’API, non un linguaggio di programmazione
Il DOM non è un linguaggio.
Non è neppure una parte del linguaggio JavaScript in senso stretto. È un insieme di interfacce fornite dall’ambiente che ospita il codice, tipicamente il browser.
La differenza diventa evidente con questa istruzione:
const titolo = document.querySelector("h1");
La sintassi JavaScript, la dichiarazione const e l’assegnazione appartengono al linguaggio. document e querySelector(), invece, sono disponibili perché l’ambiente browser espone il DOM.
Questo è anche un buon esempio della distinzione più generale spiegata nella nostra guida alle API: un’interfaccia stabilisce come un software può interagire con qualcosa senza richiedere che il linguaggio stesso implementi internamente quella risorsa.
Come il browser trasforma l’HTML nel DOM
Per capire davvero il Document Object Model bisogna seguire ciò che succede quando il browser riceve una pagina.
Il markup HTML viene analizzato dal parser. Durante questo processo il browser interpreta elementi, testo e relazioni e costruisce progressivamente l’albero del documento.
La formula più utile da ricordare è:
HTML ricevuto → parsing → DOM
Il punto importante è che questo processo non equivale a copiare esattamente il sorgente all’interno di DevTools. Le regole del parser HTML possono correggere o riorganizzare determinate strutture, e JavaScript può modificare il documento dopo il parsing.
Dal codice HTML al parsing
Supponiamo che il server restituisca:
<body>
<main>
<h1>Il mio articolo</h1>
<p>Testo iniziale</p>
</main>
</body>
Il parser riconosce le relazioni gerarchiche:
bodycontienemain;maincontieneh1ep;h1epcontengono a loro volta testo.
Il risultato è un albero sul quale il browser e le API possono lavorare.
Quando poi uno script esegue:
document.querySelector("p").textContent = "Testo aggiornato";
il paragrafo presente nel DOM cambia.
Il file HTML ricevuto dal server, invece, non viene magicamente riscritto sul server.
HTML sorgente e DOM non sono necessariamente identici
Questa differenza è fondamentale quando utilizzi gli strumenti per sviluppatori.
Il sorgente HTML rappresenta ciò che è stato inizialmente ricevuto. Il DOM rappresenta invece lo stato corrente della struttura interpretata dal browser.
Chrome spiega questa distinzione in modo molto diretto nella propria guida su HTML e DOM: HTML descrive il contenuto iniziale, mentre il DOM descrive quello corrente attraverso una struttura ad albero.
Le due rappresentazioni possono differire perché:
- il parser ha applicato le regole HTML;
- JavaScript ha aggiunto o eliminato elementi;
- uno script ha modificato testo o attributi;
- componenti e tecnologie della piattaforma hanno prodotto ulteriori strutture.
Per questo “Visualizza sorgente pagina” e il pannello Elements di DevTools non sono semplicemente due modi grafici di vedere esattamente la stessa cosa.
Come è strutturato il DOM: document, elementi e nodi
Un DOM viene normalmente rappresentato come un albero di nodi. Questa metafora non è soltanto didattica: le relazioni gerarchiche sono una parte essenziale del modello.
Ogni nodo occupa una posizione e può avere, quando previsto dal suo tipo, un padre, dei figli e dei nodi vicini.
Capire questa struttura rende molto più semplici sia la selezione degli elementi sia le successive manipolazioni con JavaScript.
Document e nodo radice
Nel codice del browser incontri spesso:
document
document rappresenta il documento caricato nella finestra corrente ed è il punto di ingresso di moltissime operazioni sul DOM.
Per esempio:
document.querySelector("main");
cerca un elemento main all’interno del documento.
La struttura possiede poi un elemento documento, normalmente <html> in una pagina HTML, dal quale discende il resto degli elementi.
Element, Text e altri tipi di nodo
“Elemento” e “nodo” vengono spesso usati come sinonimi, ma tecnicamente non indicano esattamente la stessa cosa.
Un elemento è un tipo di nodo.
Nel modello puoi incontrare, tra gli altri:
| Tipo | Esempio | Ruolo |
|---|---|---|
Document | documento corrente | rappresenta il documento |
Element | <p>, <main>, <button> | rappresenta un elemento |
Text | testo dentro un paragrafo | rappresenta contenuto testuale |
Comment | <!-- nota --> | rappresenta un commento |
Gli attributi sono esposti attraverso l’interfaccia Attr, ma non vanno immaginati semplicemente come normali figli dell’elemento.
Questa distinzione spiega anche perché:
element.children
e:
element.childNodes
possono produrre risultati differenti.
children considera gli elementi figli; childNodes può includere altri tipi di nodo, come i nodi di testo.
Parent, child, sibling, ancestor e descendant
Le relazioni più importanti dell’albero DOM sono abbastanza intuitive.
Se abbiamo:
<main> <h1>Titolo</h1> <p>Testo</p> </main>
h1 e p sono figli di main.
main è il loro parent.
h1 e p sono sibling, cioè nodi fratelli.
Un elemento più in alto nella gerarchia è un ancestor; uno che discende da un altro nodo è un descendant.
Questi concetti diventano molto utili quando inizi a spostarti nel documento o a limitare una ricerca a una parte specifica dell’albero.
DOM e JavaScript: qual è la relazione
JavaScript è il linguaggio usato più frequentemente nel browser per interagire con il DOM, ma dire che “il DOM è JavaScript” porta a un modello mentale sbagliato.
Il browser mette a disposizione oggetti e interfacce; JavaScript li utilizza. Questa separazione spiega perché lo stesso linguaggio possa essere eseguito anche in runtime come Node.js, dove l’oggetto document non è disponibile per default.
Se vuoi approfondire la distinzione tra linguaggio ECMAScript e capacità offerte dal browser, la nostra guida a JavaScript affronta proprio questo punto.
Perché il DOM non fa parte del core JavaScript
JavaScript definisce costrutti come:
const nome = "Luca";
function saluta() {
return `Ciao ${nome}`;
}
Non serve alcun DOM per eseguirli.
Questa istruzione, invece:
document.querySelector("#menu");
richiede un ambiente che fornisca document e l’interfaccia associata.
Ecco perché un runtime JavaScript lato server può comprendere perfettamente const, funzioni, oggetti e Promise senza avere automaticamente accesso alla pagina mostrata nel browser.
L’oggetto document
Per chi inizia, document è il punto d’ingresso più importante.
Da qui puoi, per esempio:
document.querySelector(".card");
document.querySelectorAll(".card");
document.getElementById("menu");
document.createElement("li");
Sono operazioni diverse, ma condividono la stessa idea: interrogare o modificare il documento attraverso il modello che il browser espone.
Come selezionare gli elementi del DOM
Prima di modificare un elemento, normalmente devi ottenere un riferimento a quell’oggetto.
I metodi disponibili sono numerosi, ma per comprendere il meccanismo non serve memorizzarli tutti. querySelector(), querySelectorAll() e getElementById() coprono già molti casi comuni.
La documentazione MDN di querySelector() specifica che il metodo restituisce il primo elemento che corrisponde al selettore CSS fornito, oppure null se non trova corrispondenze.
querySelector() e querySelectorAll()
Con:
const titolo = document.querySelector("h1");
cerchiamo il primo h1.
Possiamo usare anche selettori CSS più specifici:
const pulsante = document.querySelector(".hero .cta");
Se invece vogliamo tutti gli elementi che corrispondono a un selettore:
const cards = document.querySelectorAll(".card");
otteniamo una raccolta degli elementi corrispondenti.
Una buona abitudine è limitare la selezione a ciò che serve davvero. Un selettore molto generico applicato indiscriminatamente a un documento enorme può produrre più lavoro e riferimenti di quanti ne siano realmente necessari.
getElementById()
Quando conosci l’ID di un elemento puoi utilizzare:
const menu = document.getElementById("menu");
Il metodo esprime in modo molto diretto ciò che stiamo cercando.
Non esiste però una regola secondo cui getElementById() debba sostituire sempre querySelector() o viceversa. La scelta dipende dal tipo di selezione e dalla leggibilità del codice.
Come modificare il DOM con JavaScript
Una volta ottenuto un riferimento puoi cambiare lo stato del documento.
È qui che il DOM diventa concretamente il punto di contatto tra logica JavaScript e interfaccia visualizzata nel browser.
Puoi intervenire su testo, attributi, classi, struttura e molti altri aspetti. Questo non significa che ogni modifica debba essere eseguita via JavaScript: quando struttura e semantica possono essere definite direttamente in HTML, partire da un markup corretto tende a essere più semplice e robusto.
Modificare testo, classi e attributi
Per cambiare testo semplice puoi usare textContent:
const messaggio = document.querySelector("#messaggio");
messaggio.textContent = "Operazione completata";
Per aggiungere una classe:
messaggio.classList.add("successo");
oppure alternarla:
messaggio.classList.toggle("attivo");
Per un attributo:
const link = document.querySelector("a");
link.setAttribute("aria-current", "page");
Quando devi inserire semplice testo proveniente da dati esterni, textContent evita anche di trattarlo come markup HTML. innerHTML ha casi d’uso legittimi, ma richiede molta più attenzione se il contenuto può includere dati non affidabili.
Creare e aggiungere nuovi elementi
Puoi creare un elemento che non esiste ancora:
const voce = document.createElement("li");
voce.textContent = "Nuova voce";
A questo punto l’elemento esiste come oggetto, ma non fa ancora parte della struttura mostrata.
Per inserirlo:
const lista = document.querySelector("#menu");
lista.appendChild(voce);
Il DOM è stato modificato e il browser può riflettere il cambiamento nell’interfaccia.
Rimuovere elementi
Un elemento può anche essere eliminato:
const avviso = document.querySelector(".avviso");
avviso.remove();
Sono tutte operazioni differenti, ma il modello è sempre lo stesso:
trova un nodo → ottieni il riferimento → modifica la struttura o lo stato
Eventi DOM: come una pagina reagisce all’utente
Una pagina interattiva non deve soltanto modificare elementi. Deve sapere quando eseguire una determinata azione.
Gli eventi risolvono questo problema.
Un clic, la pressione di un tasto, l’invio di un form o molte altre azioni possono produrre eventi ai quali il codice può reagire. Il DOM Standard comprende anche il modello degli eventi e l’interfaccia EventTarget.
addEventListener()
Il modo normalmente consigliato per registrare un listener è addEventListener().
La relativa documentazione MDN descrive il metodo come il meccanismo che associa una funzione da eseguire quando un determinato evento viene consegnato al target.
Esempio:
const pulsante = document.querySelector("#saluta");
pulsante.addEventListener("click", () => {
console.log("Clic ricevuto");
});
Lo script non resta bloccato in attesa del clic. Registra il listener; quando l’evento si verifica, l’ambiente può eseguire la funzione associata.
Dal click alla modifica del DOM
Possiamo unire selezione, evento e modifica:
const pulsante = document.querySelector("#saluta");
const messaggio = document.querySelector("#messaggio");
pulsante.addEventListener("click", () => {
messaggio.textContent = "Ciao!";
});
Il flusso diventa:
utente → click → evento → listener → callback JavaScript → modifica del DOM → interfaccia aggiornata
Questa sequenza è alla base di menu, accordion, filtri, finestre modali, form interattivi e moltissimi altri componenti.
Esempio completo: HTML, DOM e JavaScript insieme
Un singolo esempio completo è più utile di una lunga lista di metodi isolati.
Costruiamo un piccolo componente in cui l’utente può cambiare lo stato di un messaggio.
Partiamo dall’HTML:
<button id="cambia-stato" type="button"> Cambia stato </button> <p id="stato"> Stato iniziale </p> <script defer src="app.js"></script>
Il browser analizza il markup e crea nel DOM il pulsante e il paragrafo.
Nel file app.js inseriamo:
const pulsante = document.querySelector("#cambia-stato");
const stato = document.querySelector("#stato");
pulsante.addEventListener("click", () => {
stato.textContent = "Stato aggiornato";
stato.classList.add("attivo");
});
Che cosa succede realmente?
- HTML descrive gli elementi.
- Il parser costruisce il DOM.
querySelector()recupera i due elementi.addEventListener()registra la funzione per il clic.- L’utente fa clic.
- La callback modifica testo e classe del paragrafo.
- Il DOM corrente è diverso dallo stato iniziale.
Il passaggio decisivo è proprio questo:
HTML iniziale → DOM costruito → JavaScript interagisce con le Web API → evento → modifica → nuovo stato del DOM
Se questo modello è chiaro, gran parte della programmazione front-end di base smette di sembrare una serie di funzioni scollegate.

DOM e performance: quando un albero grande diventa un problema
Il numero di elementi presenti nel documento può influire sulle prestazioni, ma “DOM grande = pagina lenta” è una semplificazione troppo aggressiva.
Un albero molto esteso può aumentare memoria utilizzata e lavoro richiesto da calcoli di stile e layout. Profondità e numero di elementi vanno però letti insieme alle operazioni che il browser deve realmente eseguire.
La documentazione corrente di Chrome sull’insight Optimize DOM size è particolarmente utile perché supera la vecchia lettura basata soltanto su un numero statico di nodi.
Un DOM grande non è automaticamente lento
Un albero profondo può essere un sintomo di markup eccessivamente annidato, ma la profondità da sola non dimostra un problema di performance.
Allo stesso modo una pagina complessa può legittimamente richiedere molti elementi.
Il problema pratico emerge quando quella struttura contribuisce a operazioni costose: grandi ricalcoli degli stili, layout pesanti, molte modifiche ripetute o selezioni troppo generiche eseguite continuamente.
Il criterio corretto è quindi:
misura il costo reale prima di ottimizzare il conteggio per il solo gusto di ridurre un numero.
Cosa misura oggi Chrome con Optimize DOM size
Per anni molte guide hanno ripetuto le vecchie soglie dell’audit Lighthouse che segnalava un numero elevato di nodi.
Quell’audit è stato sostituito dall’insight Optimize DOM size. La diagnosi moderna prende ancora in considerazione numero totale degli elementi, profondità e numero massimo di figli, ma il fallimento dell’insight è collegato alla presenza di operazioni significative di layout o ricalcolo degli stili.
Questa differenza è importante.
Una pagina non diventa “sbagliata” automaticamente appena supera una soglia universale. Devi identificare quale lavoro sul rendering sta costando tempo e se la struttura del DOM contribuisce realmente al problema.
Come ridurre il costo del DOM senza ottimizzazioni inutili
Quando l’analisi mostra un problema reale, gli interventi sensati possono comprendere:
- rimuovere contenitori e annidamenti che non hanno funzione;
- non creare anticipatamente migliaia di elementi che l’utente non utilizzerà;
- virtualizzare liste molto grandi quando lo scenario lo giustifica;
- evitare modifiche ripetute che provocano inutilmente nuovi calcoli di layout;
- limitare selezioni e operazioni alla parte di documento necessaria;
- verificare la complessità dei CSS insieme alla struttura.
Il punto è ridurre lavoro reale e complessità inutile, non inseguire un punteggio isolato.
DOM e SEO: cosa vede realmente Google
Il DOM interessa anche la SEO quando contenuti e link vengono generati o modificati tramite JavaScript.
Qui bisogna evitare due estremi: pensare che Google non esegua JavaScript, oppure concludere che qualunque implementazione client-side sia automaticamente equivalente a consegnare già nell’HTML tutto ciò che conta.
Google documenta esplicitamente il proprio processo nella guida alla SEO per JavaScript: dopo la scansione, le pagine idonee possono passare al rendering tramite una versione di Chromium e l’HTML renderizzato viene utilizzato anche nel processo di indicizzazione.
Scansione, rendering e indicizzazione
In una pagina server-rendered tradizionale, una grande parte del contenuto utile può essere già presente nella risposta HTML.
Una pagina fortemente dipendente da JavaScript può invece partire da un documento iniziale molto più povero e creare successivamente contenuti nel browser.
Il flusso concettuale diventa:
crawl → HTML iniziale → rendering → esecuzione JavaScript → HTML renderizzato → indicizzazione
Questo non significa che JavaScript sia un problema SEO per definizione.
Significa che devi verificare cosa esiste realmente dopo il rendering e se contenuti, link e informazioni importanti sono accessibili in modo affidabile.
Perché il contenuto importante deve essere disponibile dopo il rendering
Google afferma che, se un contenuto non è visibile nell’HTML sottoposto a rendering, non può indicizzarlo.
Per una verifica pratica non basta quindi aprire la pagina nel proprio browser e dire “io lo vedo”.
Puoi controllare:
- HTML iniziale;
- DOM nel browser;
- HTML renderizzato visto dagli strumenti Google;
- eventuali errori di risorse o JavaScript.
La distinzione è particolarmente importante con applicazioni client-side, rendering condizionale e Web Components.
Un DOM grande è un ranking factor?
Non esiste una regola Google del tipo:
più nodi DOM = ranking peggiore
La dimensione del DOM può contribuire a problemi di performance e una cattiva implementazione JavaScript può rendere contenuti o link meno affidabili per il rendering e la scansione. Sono però meccanismi differenti.
Trasformare una vecchia soglia Lighthouse in un presunto “limite SEO” significa confondere uno strumento diagnostico per le prestazioni con i sistemi di ranking.
DOM, Shadow DOM e BOM: non sono la stessa cosa
Quando inizi ad approfondire il front-end incontrerai termini molto simili. Non serve studiarli tutti insieme, ma è utile distinguere almeno DOM, Shadow DOM e BOM.
Il DOM rappresenta il documento e le interfacce necessarie per lavorare con la relativa struttura. Shadow DOM introduce invece alberi separati collegati a un elemento host e viene utilizzato soprattutto nel modello dei Web Components.
Cos’è lo Shadow DOM
Uno shadow tree è un albero DOM la cui radice è una ShadowRoot.
L’idea è consentire a un componente di possedere una struttura interna maggiormente isolata dal documento circostante.
Un esempio essenziale:
const host = document.querySelector("#componente");
const shadow = host.attachShadow({ mode: "open" });
const testo = document.createElement("p");
testo.textContent = "Contenuto interno";
shadow.appendChild(testo);
Non significa che lo Shadow DOM sia un DOM completamente scollegato dal documento. Il relativo host fa parte di un altro albero e crea il collegamento con la struttura circostante.
Per una guida introduttiva al DOM, però, è sufficiente conoscere la distinzione: non serve studiare subito slot, composizione degli alberi e tutti i dettagli dei Web Components.
Differenza tra DOM e BOM
Il termine BOM, Browser Object Model, viene normalmente usato per descrivere le API e gli oggetti legati al browser e alla finestra, anziché alla struttura del documento.
Per esempio:
window.location window.history navigator
appartengono a un’area concettualmente diversa da operazioni come:
document.querySelector()
La separazione non è sempre presentata nello stesso modo in tutta la documentazione didattica moderna, ma come modello mentale resta utile:
DOM → documento browser API / tradizionale BOM → ambiente del browser JavaScript → linguaggio che può usare queste interfacce
FAQ sul Document Object Model
Le domande più comuni sul DOM nascono quasi tutte dalla sovrapposizione fra HTML, JavaScript e ciò che il browser mette a disposizione. Chiarire questi confini evita molti errori quando si passa dagli esempi introduttivi a pagine reali.
Il DOM fa parte di JavaScript?
No. JavaScript può utilizzare il DOM nel browser, ma il Document Object Model è un insieme di interfacce della piattaforma, non una caratteristica del core ECMAScript.
È per questo che JavaScript può essere eseguito anche in ambienti che non possiedono un oggetto document.
Qual è la differenza tra HTML e DOM?
HTML descrive il documento attraverso markup.
Il DOM è la rappresentazione strutturata corrente che il browser costruisce e mette a disposizione delle API.
Il sorgente HTML iniziale e il DOM possono quindi differire dopo il parsing o in seguito a modifiche eseguite dagli script.
Cosa significa manipolare il DOM?
Significa leggere o cambiare il modello del documento attraverso le API disponibili.
Puoi, per esempio, modificare un testo, aggiungere una classe, creare un elemento, spostare un nodo o eliminarlo.
Un DOM grande rallenta sempre il sito?
No.
Una struttura molto grande può aumentare memoria e costo di alcune operazioni, ma il problema va verificato misurando layout, style recalculation, interazioni e lavoro effettivamente eseguito dal browser.
Ridurre nodi senza identificare il collo di bottiglia può produrre poco o nessun beneficio.
Il DOM influenza la SEO?
Può avere conseguenze indirette quando JavaScript determina quali contenuti e link sono presenti nell’HTML renderizzato o quando problemi di performance peggiorano l’esperienza della pagina.
Non esiste però una semplice regola SEO basata sul numero di nodi presenti nel DOM.
Conclusione
Capire il DOM significa capire che cosa c’è tra il file HTML e la pagina viva che utilizzi nel browser.
HTML descrive inizialmente la struttura. Il parser costruisce un albero di nodi. Il browser espone quel documento attraverso interfacce programmabili. JavaScript può selezionare gli oggetti, ascoltare eventi e modificarne lo stato.
Il modello essenziale da ricordare è quindi:
HTML → parsing → DOM → selezione → evento o logica JavaScript → modifica → nuovo stato del documento
Una volta compreso questo passaggio, metodi come querySelector(), createElement() o addEventListener() smettono di essere istruzioni da imparare a memoria e diventano semplicemente strumenti per lavorare con lo stesso modello.
Se stai costruendo queste basi partendo dall’inizio, il percorso più sensato è consolidare prima HTML e poi approfondire JavaScript: il DOM è esattamente il punto in cui i due livelli iniziano a interagire.