Volver al inicio
Manipulación del DOM

Manipulación del DOM

Aprende a interactuar con el HTML de tu página web usando JavaScript. El DOM te permite seleccionar, modificar, crear y eliminar elementos dinámicamente.

1. ¿Qué es el DOM?

El DOM (Document Object Model) es una representación en forma de árbol de tu página HTML. JavaScript puede acceder y modificar este árbol para cambiar dinámicamente el contenido, estilos y estructura de la página.

Ejemplo: Cuando tienes un <div> en tu HTML, JavaScript lo ve como un objeto que puedes manipular.

HTML y JavaScript trabajando juntoshtml
1<!-- HTML -->
2<div id="mensaje">
3 <h1>¡Hola!</h1>
4 <p class="texto">Bienvenido a la web</p>
5</div>
6
7<script>
8// JavaScript puede acceder y modificar estos elementos
9const div = document.getElementById('mensaje');
10const parrafo = document.querySelector('.texto');
11
12// Cambiar el texto
13parrafo.textContent = '¡Texto modificado desde JavaScript!';
14</script>

2. Seleccionar Elementos

Antes de modificar un elemento, necesitas seleccionarlo. JavaScript ofrece varios métodos para hacerlo:

querySelector y querySelectorAll

Los métodos más recomendados y modernos. Usan selectores CSS.

querySelector - Selectores CSSjavascript
1// querySelector - Devuelve el PRIMER elemento que coincide
2const titulo = document.querySelector('h1');
3const primerBoton = document.querySelector('.btn');
4const elemento = document.querySelector('#menu');
5
6// querySelectorAll - Devuelve TODOS los elementos que coinciden
7const todosLosParrafos = document.querySelectorAll('p');
8const todosBotones = document.querySelectorAll('.btn');
9
10// Iterar sobre los elementos
11todosLosParrafos.forEach(parrafo => {
12 console.log(parrafo.textContent);
13});

Otros métodos de selección

Métodos tradicionalesjavascript
1// Por ID (más rápido, pero menos flexible)
2const header = document.getElementById('header');
3
4// Por clase (devuelve HTMLCollection, no Array)
5const botones = document.getElementsByClassName('btn');
6
7// Por etiqueta
8const parrafos = document.getElementsByTagName('p');
9
10// ⚠️ HTMLCollection NO es un array real
11// Para usar forEach, conviértelo a array:
12Array.from(botones).forEach(btn => {
13 console.log(btn);
14});

Recomendación

Usa querySelector y querySelectorAll en el 99% de los casos. Son más flexibles y modernos.

3. ⚠️ ¿Qué devuelven los selectores?

Es muy importante entender que los diferentes métodos de selección devuelven tipos distintos de objetos. Esto afecta qué operaciones puedes realizar sobre ellos.

Comparación de tipos de retorno

Tipos de retorno de los selectoresjavascript
1// querySelector - Devuelve UN ELEMENTO (Element) o null
2const titulo = document.querySelector('h1');
3console.log(titulo); // <h1>...</h1>
4// ✅ Puedes acceder directamente a propiedades
5titulo.textContent = 'Nuevo título';
6
7// querySelectorAll - Devuelve un NODELIST (parecido a array)
8const parrafos = document.querySelectorAll('p');
9console.log(parrafos); // NodeList(3) [p, p, p]
10// ✅ Tiene forEach
11parrafos.forEach(p => console.log(p));
12// ❌ NO tiene map, filter, reduce
13// parrafos.map(p => p.textContent); // ERROR!
14
15// getElementsByClassName - Devuelve un HTMLCOLLECTION
16const botones = document.getElementsByClassName('btn');
17console.log(botones); // HTMLCollection(2) [button.btn, button.btn]
18// ❌ NO tiene forEach ni map
19// botones.forEach(btn => console.log(btn)); // ERROR!
20
21// getElementById - Devuelve UN ELEMENTO o null
22const header = document.getElementById('header');
23console.log(header); // <header id="header">...</header>

Tabla comparativa

Método Devuelve Tiene forEach Métodos Array
querySelector() Element N/A (es un objeto) N/A
querySelectorAll() NodeList ✅ Sí ❌ No
getElementById() Element N/A (es un objeto) N/A
getElementsByClassName() HTMLCollection ❌ No ❌ No

Convertir a Array para usar métodos completos

Convertir NodeList/HTMLCollection a Arrayjavascript
1// Problema: querySelectorAll devuelve NodeList sin map/filter
2const parrafos = document.querySelectorAll('p');
3// parrafos.map(p => p.textContent); // ❌ ERROR!
4
5// Solución 1: Array.from()
6const textos1 = Array.from(parrafos).map(p => p.textContent);
7console.log(textos1); // ['Texto 1', 'Texto 2', 'Texto 3']
8
9// Solución 2: Spread operator [...]
10const textos2 = [...parrafos].map(p => p.textContent);
11
12// Solución 3: Array.prototype.slice
13const textos3 = Array.prototype.slice.call(parrafos).map(p => p.textContent);
14
15// Lo mismo para HTMLCollection
16const botones = document.getElementsByClassName('btn');
17const arrayBotones = Array.from(botones);
18arrayBotones.forEach(btn => btn.classList.add('activo'));
19arrayBotones.filter(btn => btn.disabled === false);
20arrayBotones.map(btn => btn.textContent);

Consejo práctico

Si necesitas usar métodos de arrays (map, filter, reduce), convierte inmediatamente:

const elementos = Array.from(document.querySelectorAll('.item'));

4. Modificar Contenido

Una vez seleccionado un elemento, puedes modificar su contenido usando textContent o innerHTML.

Modificar texto y HTMLjavascript
1const titulo = document.querySelector('h1');
2const contenedor = document.querySelector('#contenedor');
3
4// textContent - Solo texto (más seguro)
5titulo.textContent = '¡Nuevo título!';
6
7// innerHTML - Puede incluir HTML (cuidado con XSS)
8contenedor.innerHTML = '<p>Nuevo <strong>párrafo</strong></p>';
9
10// Leer el contenido
11console.log(titulo.textContent); // "¡Nuevo título!"
12
13// Diferencia entre textContent e innerHTML
14const div = document.querySelector('#ejemplo');
15div.innerHTML = '<strong>Negrita</strong>';
16console.log(div.textContent); // "Negrita" (sin etiquetas)
17console.log(div.innerHTML); // "<strong>Negrita</strong>" (con etiquetas)

¡Cuidado con innerHTML!

Si usas innerHTML con datos del usuario, puedes crear vulnerabilidades XSS. Usa textContent cuando solo necesites texto.

5. Modificar Atributos

Trabajar con atributosjavascript
1const imagen = document.querySelector('img');
2const enlace = document.querySelector('a');
3const input = document.querySelector('input');
4
5// Cambiar atributos
6imagen.src = 'nueva-imagen.jpg';
7imagen.alt = 'Descripción de la imagen';
8
9enlace.href = 'https://ejemplo.com';
10enlace.target = '_blank';
11
12input.value = 'Texto por defecto';
13input.placeholder = 'Escribe algo...';
14
15// getAttribute y setAttribute (forma genérica)
16const dataId = enlace.getAttribute('data-id');
17enlace.setAttribute('data-id', '123');
18
19// Verificar si tiene un atributo
20if (enlace.hasAttribute('target')) {
21 console.log('El enlace se abre en nueva pestaña');
22}
23
24// Eliminar un atributo
25enlace.removeAttribute('target');

6. Trabajar con Clases CSS

El objeto classList es la forma moderna y recomendada de trabajar con clases CSS.

classList - Manipular clases CSSjavascript
1const boton = document.querySelector('.btn');
2
3// Añadir una clase
4boton.classList.add('activo');
5boton.classList.add('btn-grande', 'destacado'); // Múltiples clases
6
7// Eliminar una clase
8boton.classList.remove('activo');
9
10// Alternar una clase (toggle)
11boton.classList.toggle('activo'); // Si existe, la elimina. Si no, la añade
12
13// Verificar si tiene una clase
14if (boton.classList.contains('activo')) {
15 console.log('El botón está activo');
16}
17
18// Reemplazar una clase
19boton.classList.replace('btn-grande', 'btn-pequeño');
20
21// Ver todas las clases
22console.log(boton.classList); // DOMTokenList ["btn", "activo"]

Modificar estilos directamente

Modificar estilos (menos recomendado)javascript
1const caja = document.querySelector('.caja');
2
3// Modificar estilos inline
4caja.style.backgroundColor = '#3b82f6';
5caja.style.color = 'white';
6caja.style.padding = '20px';
7caja.style.borderRadius = '10px';
8
9// Propiedades CSS con guiones → camelCase
10caja.style.fontSize = '18px'; // font-size
11caja.style.marginTop = '10px'; // margin-top
12
13// ⚠️ Esto crea estilos inline (no recomendado)
14// Mejor usar classList para añadir/quitar clases CSS

Buena práctica

Usa classList para cambiar estilos. Define las clases CSS en tu archivo CSS y añádelas/quítalas con JavaScript. Es más mantenible.

7. Crear y Añadir Elementos

Crear elementos desde cerohtml
1<!-- HTML inicial -->
2<div id="contenedor">
3 <p>Primer párrafo existente</p>
4</div>
5
6<style>
7 #contenedor {
8 border: 2px solid #3b82f6;
9 padding: 20px;
10 margin: 20px 0;
11 }
12
13 .destacado {
14 background-color: #fbbf24;
15 color: #1f2937;
16 padding: 10px;
17 border-radius: 5px;
18 font-weight: bold;
19 }
20</style>
21
22<script>
23// 1. Crear un elemento
24const nuevoParrafo = document.createElement('p');
25
26// 2. Configurar el elemento
27nuevoParrafo.textContent = 'Este es un nuevo párrafo';
28nuevoParrafo.classList.add('destacado');
29
30// 3. Añadir al DOM
31const contenedor = document.querySelector('#contenedor');
32contenedor.append(nuevoParrafo); // Al final del contenedor
33
34// Resultado:
35// <div id="contenedor">
36// <p>Primer párrafo existente</p>
37// <p class="destacado">Este es un nuevo párrafo</p>
38// </div>
39</script>

Diferentes métodos para añadir elementos

Comparación de métodos para insertarhtml
1<!-- HTML inicial -->
2<div id="contenedor">
3 <p>Párrafo del medio</p>
4</div>
5
6<script>
7const contenedor = document.querySelector('#contenedor');
8
9// 1. append() - Añade AL FINAL del contenedor
10const p1 = document.createElement('p');
11p1.textContent = 'Al final';
12contenedor.append(p1);
13
14// 2. prepend() - Añade AL PRINCIPIO del contenedor
15const p2 = document.createElement('p');
16p2.textContent = 'Al principio';
17contenedor.prepend(p2);
18
19// 3. before() - Añade ANTES del contenedor (como hermano)
20const p3 = document.createElement('p');
21p3.textContent = 'Antes del contenedor';
22contenedor.before(p3);
23
24// 4. after() - Añade DESPUÉS del contenedor (como hermano)
25const p4 = document.createElement('p');
26p4.textContent = 'Después del contenedor';
27contenedor.after(p4);
28
29// Resultado final:
30// <p>Antes del contenedor</p>
31// <div id="contenedor">
32// <p>Al principio</p>
33// <p>Párrafo del medio</p>
34// <p>Al final</p>
35// </div>
36// <p>Después del contenedor</p>
37</script>

Ejemplo completo: Crear elementos desde JavaScript

En este ejemplo, JavaScript crea TODO desde cero: el contenedor, las tarjetas, y todo su contenido. El HTML está prácticamente vacío.

📄 index.html

index.htmlhtml
1<!DOCTYPE html>
2<html lang="es">
3<head>
4 <meta charset="UTF-8">
5 <title>Crear Tarjetas</title>
6 <style>
7 body {
8 font-family: Arial, sans-serif;
9 padding: 20px;
10 background-color: #f5f5f5;
11 }
12
13 .tarjeta {
14 background-color: white;
15 margin: 15px 0;
16 }
17 </style>
18</head>
19<body>
20 <!-- Body completamente vacío -->
21 <!-- JavaScript creará TODO -->
22 <script src="app.js"></script>
23</body>
24</html>

📄 app.js

app.jsjavascript
1// 1. Crear el contenedor principal
2const contenedor = document.createElement('div');
3contenedor.id = 'contenedor';
4
5// Aplicar estilos con .style
6contenedor.style.maxWidth = '800px';
7contenedor.style.margin = '0 auto';
8
9// 2. Añadir el contenedor al body
10document.body.append(contenedor);
11
12// 3. Función para crear tarjetas
13function crearTarjeta(titulo, descripcion) {
14 // Crear elementos
15 const tarjeta = document.createElement('div');
16 const h3 = document.createElement('h3');
17 const p = document.createElement('p');
18 const boton = document.createElement('button');
19
20 // Configurar contenido
21 h3.textContent = titulo;
22 p.textContent = descripcion;
23 boton.textContent = 'Ver más';
24
25 // Añadir clase CSS (definida en HTML)
26 tarjeta.classList.add('tarjeta');
27
28 // Añadir estilos con .style (inline)
29 tarjeta.style.border = '1px solid #ddd';
30 tarjeta.style.borderRadius = '8px';
31 tarjeta.style.padding = '20px';
32 tarjeta.style.boxShadow = '0 2px 4px rgba(0,0,0,0.1)';
33
34 h3.style.margin = '0 0 10px 0';
35 h3.style.color = '#333';
36
37 p.style.color = '#666';
38 p.style.marginBottom = '15px';
39
40 boton.style.padding = '8px 16px';
41 boton.style.border = 'none';
42 boton.style.borderRadius = '4px';
43 boton.style.backgroundColor = '#3b82f6';
44 boton.style.color = 'white';
45 boton.style.cursor = 'pointer';
46
47 // Ensamblar la tarjeta
48 tarjeta.append(h3, p, boton);
49
50 return tarjeta;
51}
52
53// 4. Crear y añadir varias tarjetas
54contenedor.append(
55 crearTarjeta(
56 'JavaScript',
57 'Lenguaje de programación para web'
58 )
59);
60
61contenedor.append(
62 crearTarjeta(
63 'Manipulación del DOM',
64 'Crear y modificar elementos HTML'
65 )
66);
67
68contenedor.append(
69 crearTarjeta(
70 'Eventos',
71 'Interactuar con acciones del usuario'
72 )
73);

La POTENCIA del dom

Fíjate que el HTML está prácticamente vacío. JavaScript crea:

  • El <div id="contenedor"> principal
  • Cada <div class="tarjeta">
  • Los elementos internos: <h3>, <p>, <button>
  • Añade clases CSS automáticamente

Esto es lo que hacen los frameworks modernos (React, Vue, ,Nextjs, Svelte) pero de forma más avanzada.

8. Eliminar Elementos

Eliminar elementos del DOMjavascript
1const elemento = document.querySelector('.eliminar');
2
3// Forma moderna (recomendada)
4elemento.remove();
5
6// Forma antigua (todavía funcional)
7elemento.parentNode.removeChild(elemento);
8
9// Eliminar todos los hijos de un contenedor
10const contenedor = document.querySelector('#contenedor');
11contenedor.innerHTML = ''; // Vaciar completamente
12
13// O usando un bucle
14while (contenedor.firstChild) {
15 contenedor.removeChild(contenedor.firstChild);
16}

9. Navegar por el DOM

Relaciones entre elementosjavascript
1const elemento = document.querySelector('.item');
2
3// Padres
4elemento.parentNode; // Nodo padre
5elemento.parentElement; // Elemento padre
6elemento.closest('.contenedor'); // Ancestro más cercano que coincide
7
8// Hijos
9elemento.children; // HTMLCollection de hijos
10elemento.firstElementChild; // Primer hijo
11elemento.lastElementChild; // Último hijo
12elemento.childNodes; // Todos los nodos (incluye texto)
13
14// Hermanos
15elemento.nextElementSibling; // Siguiente hermano
16elemento.previousElementSibling; // Hermano anterior

10. Ejercicios Prácticos

Ejercicio 1: Cambiar Texto y Estilos

Crea una página HTML con un título y un botón. Al hacer clic en el botón:

  • Cambia el texto del título
  • Añade la clase destacado al título
  • Cambia el color de fondo del botón
Ver solución
Solución Ejercicio 1html
1<!DOCTYPE html>
2<html>
3<head>
4 <style>
5 .destacado {
6 color: #3b82f6;
7 font-size: 2em;
8 }
9 </style>
10</head>
11<body>
12 <h1 id="titulo">Título Original</h1>
13 <button id="btn">Cambiar</button>
14
15 <script>
16 const titulo = document.querySelector('#titulo');
17 const boton = document.querySelector('#btn');
18
19 boton.addEventListener('click', () => {
20 // Cambiar texto
21 titulo.textContent = '¡Título Cambiado!';
22
23 // Añadir clase
24 titulo.classList.add('destacado');
25
26 // Cambiar estilo del botón
27 boton.style.backgroundColor = '#10b981';
28 boton.style.color = 'white';
29 });
30 </script>
31</body>
32</html>

Ejercicio 2: Lista de Tareas

Crea una lista de tareas simple:

  • Un input para escribir la tarea
  • Un botón "Añadir" que cree un nuevo elemento <li> con el texto del input
  • Cada tarea debe añadirse a una lista <ul>
Ver solución
Solución Ejercicio 2html
1<!DOCTYPE html>
2<html>
3<body>
4 <input type="text" id="input" placeholder="Nueva tarea...">
5 <button id="agregar">Añadir</button>
6 <ul id="lista"></ul>
7
8 <script>
9 const input = document.querySelector('#input');
10 const boton = document.querySelector('#agregar');
11 const lista = document.querySelector('#lista');
12
13 boton.addEventListener('click', () => {
14 const texto = input.value.trim();
15
16 if (texto === '') {
17 alert('Escribe una tarea');
18 return;
19 }
20
21 // Crear nuevo elemento li
22 const tarea = document.createElement('li');
23 tarea.textContent = texto;
24
25 // Añadir a la lista
26 lista.append(tarea);
27
28 // Limpiar input
29 input.value = '';
30 input.focus();
31 });
32
33 // Bonus: Añadir con Enter
34 input.addEventListener('keypress', (e) => {
35 if (e.key === 'Enter') {
36 boton.click();
37 }
38 });
39 </script>
40</body>
41</html>

Ejercicio 3: Galería de Imágenes

Crea una galería que:

  • Muestre miniaturas de imágenes
  • Al hacer clic en una miniatura, cambie la imagen principal
  • Use classList.add() para resaltar la miniatura activa
Ver solución
Solución Ejercicio 3html
1<!DOCTYPE html>
2<html>
3<head>
4 <style>
5 #principal { width: 400px; display: block; }
6 .miniatura { width: 80px; cursor: pointer; margin: 5px; }
7 .activa { border: 3px solid #3b82f6; }
8 </style>
9</head>
10<body>
11 <img id="principal" src="img1.jpg" alt="Imagen principal">
12 <div id="miniaturas">
13 <img class="miniatura activa" src="img1.jpg" data-img="img1.jpg">
14 <img class="miniatura" src="img2.jpg" data-img="img2.jpg">
15 <img class="miniatura" src="img3.jpg" data-img="img3.jpg">
16 </div>
17
18 <script>
19 const principal = document.querySelector('#principal');
20 const miniaturas = document.querySelectorAll('.miniatura');
21
22 miniaturas.forEach(mini => {
23 mini.addEventListener('click', () => {
24 // Cambiar imagen principal
25 const nuevaSrc = mini.getAttribute('data-img');
26 principal.src = nuevaSrc;
27
28 // Quitar clase activa de todas
29 miniaturas.forEach(m => m.classList.remove('activa'));
30
31 // Añadir clase activa a la clickeada
32 mini.classList.add('activa');
33 });
34 });
35 </script>
36</body>
37</html>

Ejercicio 4: Contador con Botones

Crea un contador con tres botones:

  • Botón "+" que incremente el contador
  • Botón "-" que decremente el contador
  • Botón "Reset" que lo vuelva a 0
  • El número debe mostrarse en un elemento con id contador
Ver solución
Solución Ejercicio 4html
1<!DOCTYPE html>
2<html>
3<body>
4 <h1 id="contador">0</h1>
5 <button id="incrementar">+</button>
6 <button id="decrementar">-</button>
7 <button id="reset">Reset</button>
8
9 <script>
10 const contadorEl = document.querySelector('#contador');
11 const btnInc = document.querySelector('#incrementar');
12 const btnDec = document.querySelector('#decrementar');
13 const btnReset = document.querySelector('#reset');
14
15 let contador = 0;
16
17 function actualizarContador() {
18 contadorEl.textContent = contador;
19
20 // Bonus: Cambiar color según el valor
21 if (contador > 0) {
22 contadorEl.style.color = '#10b981';
23 } else if (contador < 0) {
24 contadorEl.style.color = '#ef4444';
25 } else {
26 contadorEl.style.color = '#64748b';
27 }
28 }
29
30 btnInc.addEventListener('click', () => {
31 contador++;
32 actualizarContador();
33 });
34
35 btnDec.addEventListener('click', () => {
36 contador--;
37 actualizarContador();
38 });
39
40 btnReset.addEventListener('click', () => {
41 contador = 0;
42 actualizarContador();
43 });
44 </script>
45</body>
46</html>