Browser APIs

El DOM

El Document Object Model es el puente entre tu HTML y tu JavaScript. Aprende a seleccionar, crear, actualizar y eliminar elementos, y a responder a las acciones de los usuarios.

beginner15 min readUpdated 15 sept 2026
js
const list = document.querySelector("#todos");
const input = document.querySelector("#todo-input");

function addTodo(text) {
  const li = document.createElement("li");
  li.textContent = text;
  list.append(li);
}

input.addEventListener("keydown", (event) => {
  if (event.key === "Enter") {
    addTodo(input.value);
    input.value = "";
  }
});
Qué es
Un árbol vivo de objetos
Construido por
El navegador, a partir de tu HTML
Selecciona con
querySelector / querySelectorAll
Reacciona con
addEventListener
Crea con
document.createElement
Costo
Trabajo de layout y paint

Practico

Prueba la manipulación del DOM

Haz clic en el botón y luego edita el código para ver cómo cambia el árbol.

Prueba la manipulación del DOM

Haz clic en el botón y luego edita el código para ver cómo cambia el árbol.

Por que importa

Por qué el DOM es importante

Tu HTML, como objetos

El navegador analiza el marcado y lo convierte en un árbol de nodos que tu código puede leer y cambiar en cualquier momento.

Feedback instantáneo

Actualiza el árbol y el navegador repinta automáticamente; sin recargar la página ni hacer viajes de ida y vuelta al servidor.

Reacciona a cualquier cosa

Clicks, escritura, scroll, cambio de tamaño, eventos de red y más, todo llega a través de un único modelo de eventos.

La imagen completa

Las tres ideas detrás del DOM

Cualquier tarea en el DOM es una combinación de los mismos tres movimientos: encontrar algo, cambiarlo o reaccionar a ello.

El árbol

Estructura

Una jerarquía de nodos donde cada elemento, atributo y fragmento de texto tiene un lugar y un padre.

Selección

Buscar y cambiar

Consulta el árbol, luego lee o escribe texto, atributos, clases y estilos en los nodos que encontraste.

Eventos

Reaccionar

Escucha eventos del usuario y del navegador, y luego ejecuta código en respuesta, idealmente mediante delegación.

El DOM de un vistazo

Qué puedes hacer con el DOM

Selección de elementos

querySelector devuelve la primera coincidencia, querySelectorAll devuelve todas las coincidencias como una lista estática.

Lectura y escritura

textContent, innerHTML, atributos y dataset te permiten inspeccionar y actualizar el contenido.

Clases y estilos

classList y la propiedad style cambian la apariencia sin tocar una hoja de estilos.

Construcción de nodos

createElement, append, prepend y remove hacen crecer o reducir el árbol según sea necesario.

Eventos

addEventListener se suscribe a clicks, input, teclado, scroll y mucho más.

Delegación de eventos

Un solo listener en un padre puede manejar eventos de todos sus hijos, incluso de aquellos añadidos posteriormente.

Una breve historia

Cómo evolucionó el DOM

  1. 1996

    El primer DOM

    Netscape y Microsoft exponen formas competitivas de programar páginas, iniciando la primera guerra de navegadores.

    96
  2. 1998

    DOM Level 1

    El W3C estandariza un modelo de árbol común y una API compartida para manipularlo.

    98
  3. 2009

    Llega querySelector

    Los selectores estilo CSS hacen que encontrar elementos sea drásticamente más simple y expresivo.

    09
  4. 2015

    classList y APIs modernas

    classList, dataset y template simplifican el trabajo diario con el DOM y reemplazan viejos trucos.

    15
  5. Hoy

    Un estándar vivo

    El DOM se mantiene como una especificación actualizada continuamente con un amplio acuerdo entre navegadores.

    Hoy

La guia completa

El DOM: Todo lo que necesitas saber

¿Qué es el DOM?

Cuando el navegador lee tu HTML, no mantiene una cadena de texto plana. Construye un árbol de objetos llamado Document Object Model. Cada elemento se convierte en un nodo con propiedades y métodos, cada atributo es accesible y cada fragmento de texto tiene su lugar. El DOM es ese árbol, y es dinámico: si lo modificas, la página se actualiza.

Es por esto que JavaScript y HTML se sienten conectados. Tu HTML describe la estructura, el navegador la convierte en objetos y JavaScript manipula esos objetos. El objeto document es el punto de entrada a todo el árbol.

El árbol de nodos

El DOM es jerárquico. El document es la raíz, <html> es su hijo, y todo lo demás cuelga debajo en una relación padre-hijo. Un nodo puede tener muchos hijos, pero solo un padre.

document
└── html
    ├── head
    │   └── title
    └── body
        ├── h1
        └── p

Existen varios tipos de nodos. Los nodos de elemento representan las etiquetas. Los nodos de texto contienen los caracteres dentro de los elementos. Los nodos de comentario representan los comentarios. La mayor parte del tiempo trabajarás con elementos, pero saber que existen los nodos de texto explica las sorpresas con los espacios en blanco y por qué childNodes puede incluir más de lo que esperas.

Seleccionando elementos

Antes de poder cambiar cualquier cosa, tienes que encontrarla. La herramienta fundamental hoy en día es querySelector, que acepta cualquier selector de CSS.

// select.js
const title = document.querySelector("h1");
const firstCard = document.querySelector(".card");
const allLinks = document.querySelectorAll("a[target='_blank']");
const byId = document.getElementById("main");

allLinks.forEach((link) => link.classList.add("external"));

querySelector devuelve el primer elemento coincidente o null. querySelectorAll devuelve una NodeList estática de todas las coincidencias, la cual es compatible con forEach pero no se actualiza cuando el DOM cambia. Los métodos más antiguos getElementById, getElementsByClassName y getElementsByTagName siguen funcionando; los dos últimos devuelven colecciones vivas que se actualizan automáticamente.

Lectura y escritura de contenido

Una vez que tienes un elemento, puedes leer o reemplazar su contenido.

// content.js
const heading = document.querySelector("#title");

heading.textContent;          // read the visible text
heading.textContent = "Hello"; // replace it, escaped as text

heading.innerHTML = "<em>Hi</em>"; // parses HTML

Usa textContent siempre que el valor provenga de un usuario, una API o cualquier lugar que no controles totalmente. Esto trata todo como texto plano y evita la inyección de marcado. innerHTML analiza una cadena como HTML, lo cual es conveniente para plantillas confiables, pero representa un riesgo grave de cross-site scripting con entradas no confiables. Si debes construir marcado a partir de datos, es preferible crear elementos y asignar textContent a cada uno.

Atributos, clases y estilos

Los atributos residen en el elemento y pueden leerse o modificarse directamente.

// attrs.js
const link = document.querySelector("a");

link.getAttribute("href");
link.setAttribute("href", "/docs");
link.dataset.userId = "42"; // data-user-id="42"

link.classList.add("active");
link.classList.toggle("open");
link.classList.remove("hidden");

link.style.color = "tomato";

classList es la forma más limpia de gestionar las clases: evita la concatenación de strings y la creación accidental de clases duplicadas. La propiedad style define estilos inline propiedad por propiedad; para cualquier aspecto temático, es preferible alternar una clase y dejar que CSS decida.

Creación, inserción y eliminación de nodos

Construyes nuevos nodos con document.createElement y los ubicas utilizando los métodos de inserción.

// build.js
const item = document.createElement("li");
item.textContent = "New task";
item.classList.add("task");

const list = document.querySelector("#todos");
list.append(item);       // add at the end
list.prepend(item);      // add at the start
item.remove();           // detach from the tree

append acepta múltiples nodos e incluso cadenas de texto, mientras que insertBefore te permite una ubicación precisa. Cuando necesites insertar muchos nodos, constrúyelos fuera del documento y adjúntalos una sola vez:

// fragment.js
const fragment = document.createDocumentFragment();
for (const name of names) {
  const li = document.createElement("li");
  li.textContent = name;
  fragment.append(li);
}
list.append(fragment);

Un DocumentFragment es un contenedor ligero que no forma parte de la página. Al adjuntarlo, se mueven todos sus hijos en una sola operación, lo que provoca mucho menos trabajo de layout que añadirlos uno por uno.

Escuchar eventos

Los eventos son la forma en que tu código responde al usuario y al navegador. Adjunta un listener con addEventListener.

// events.js
const button = document.querySelector("#save");

button.addEventListener("click", (event) => {
  event.preventDefault();
  console.log("clicked", event.target);
});

El objeto del evento contiene información útil: target es el elemento que disparó el evento, currentTarget es el elemento al que está adjunto el listener, y preventDefault() cancela el comportamiento predeterminado del navegador. Algunos eventos comunes incluyen click, input, change, submit, keydown, scroll y DOMContentLoaded.

Delegación de eventos

En lugar de asignar un listener a cada hijo, asigna uno solo al padre e inspecciona event.target. Debido a que los eventos hacen bubble (propagación) desde el objetivo hacia arriba a través de sus ancestros, el padre los detecta todos.

// delegate.js
const list = document.querySelector("#todos");

list.addEventListener("click", (event) => {
  const button = event.target.closest("button.delete");
  if (!button) return;
  button.closest("li").remove();
});

Esto es más eficiente y, fundamentalmente, sigue funcionando para los elementos añadidos después de haber asignado el listener. Para listas y tablas dinámicas, la delegación es el patrón predeterminado.

Recorriendo el árbol

A veces es necesario moverse de un nodo a sus nodos relacionados.

// traverse.js
const item = document.querySelector(".item");

item.parentElement;        // nearest ancestor element
item.children;             // child elements only
item.firstElementChild;    // first child element
item.nextElementSibling;   // next sibling element
item.closest(".card");     // nearest ancestor matching a selector

Las variantes Element omiten los nodos de texto y de comentario, que es casi siempre lo que se busca. closest es especialmente útil en los manejadores de eventos, como muestra el ejemplo de delegación.

Rendimiento y mejores prácticas

  • Agrupa tus lecturas y escrituras. Leer propiedades de diseño como offsetHeight obliga al navegador a recalcular; intercalar lecturas y escrituras provoca reflows repetidos.
  • Construye fuera del documento. Utiliza un DocumentFragment o un elemento fuera de pantalla y adjúntalo una sola vez.
  • Almacena en caché tus búsquedas. Guarda los elementos en variables en lugar de realizar consultas dentro de un bucle.
  • Prefiere las clases sobre los estilos inline. Alterna una clase y mantén la presentación en CSS.
  • Usa textContent por defecto. Utiliza innerHTML únicamente con contenido confiable y sanitizado.
  • Delega eventos para listas y cualquier elemento dinámico.
  • Elimina los listeners que ya no necesites, especialmente en páginas de larga duración, para evitar fugas de memoria.

Errores comunes

  • Consultar un elemento antes de que exista y luego preguntarse por qué es null.
  • Usar innerHTML con entradas de usuario y abrir un agujero de XSS.
  • Adjuntar un listener a cada fila en lugar de delegar el evento a la tabla.
  • Leer y escribir propiedades de diseño (layout) en el mismo bucle.
  • Confundir event.target con event.currentTarget.
  • Asumir que querySelectorAll es dinámico cuando es una captura estática.

Próximos pasos

El DOM es el punto de encuentro de todo lo que has aprendido. Combínalo con la sintaxis de ES6+ para escribir un código más limpio, luego aliméntalo con datos mediante la Fetch API y mantenlo robusto utilizando el manejo de errores. La forma más rápida de interiorizarlo es reconstruir algo pequeño —una lista de tareas, una galería filtrable o un buscador en tiempo real— utilizando únicamente vanilla JavaScript.

Establecer texto de forma segura

textContent trata la entrada como texto. innerHTML la analiza como marcado, lo que representa un riesgo de XSS con datos no confiables.

Preferido
const comment = "<b>hi</b>";
el.textContent = comment;
// renders the literal text
Evitar
const comment = "<img src=x onerror=alert(1)>";
el.innerHTML = comment;
// executes markup

Escuchar clicks

Delega en un padre para que los elementos añadidos posteriormente sigan funcionando y adjuntes un solo listener en lugar de muchos.

Preferido
list.addEventListener("click", (e) => {
  const li = e.target.closest("li");
  if (li) li.remove();
});
Evitar
document.querySelectorAll("li")
  .forEach((li) => {
    li.addEventListener("click", () => li.remove());
  });

Preguntas frecuentes

Preguntas frecuentes

Keep learning

Related topics from the roadmap.

$ comienza a aprender

Listo para aprender DOM Manipulation?

Nuestro tutorial interactivo te guia a traves de DOM Manipulation paso a paso — con quizzes y codigo real que puedes ejecutar en el navegador.