JavaScript — Seleccionar elementos del DOM
Aprende a seleccionar elementos del DOM en JavaScript con getElementById, querySelector, querySelectorAll, getElementsByClassName, matches y closest, con ejemplos y cuándo usar cada uno.
Antes de poder cambiar cualquier cosa en una página con JavaScript — actualizar texto, alternar una clase, añadir un manejador de clics — primero debes encontrar el elemento que quieres. Ese acto de encontrar se llama seleccionar un elemento del DOM. Este capítulo cubre todos los métodos que necesitas, explica qué devuelve cada uno y muestra cuándo usar cuál.
Qué significa "seleccionar un elemento"
El Document Object Model (DOM) es la representación en árbol, en tiempo real, que hace el navegador de tu HTML. Cada etiqueta se convierte en un objeto nodo que puedes leer y modificar desde JavaScript. Seleccionar es el proceso de localizar uno o más de esos nodos para guardar una referencia a ellos en una variable:
const heading = document.querySelector('h1');
// `heading` now points at the real <h1> on the page.Una vez que tienes esa referencia, todo lo demás — leer atributos y propiedades, cambiar estilos, añadir oyentes de eventos — funciona sobre ella.
Los métodos de selección se dividen en dos grupos:
- Búsquedas por ID / clase / etiqueta — rápidas, devuelven colecciones vivas (excepto
getElementById). - Búsquedas por selector CSS (
querySelector,querySelectorAll) — flexibles, aceptan cualquier selector CSS, devuelven un resultado estático.
Seleccionar un elemento por ID: getElementById
La forma más rápida de obtener un único elemento es por su id único. Devuelve el elemento, o null si no existe ningún elemento con ese ID.
const element = document.getElementById('example');
element.textContent = 'You selected the element by its ID!';Como los IDs están pensados para ser únicos, getElementById devuelve un único elemento (no una colección) y es la búsqueda más directa y de mayor rendimiento.
Si ningún elemento coincide, getElementById devuelve null. Llamar a una propiedad sobre null lanza TypeError: Cannot read properties of null. Protégete contra ello: const el = document.getElementById('maybe'); if (el) { /* ... */ }.
Seleccionar por nombre de clase: getElementsByClassName
Este método devuelve una HTMLCollection viva de todos los elementos que tienen la clase indicada. "Viva" significa que la colección se actualiza automáticamente cuando el DOM cambia.
const elements = document.getElementsByClassName('example');
Array.from(elements).forEach((element, index) => {
element.textContent = `Element ${index + 1} changed!`;
});Una HTMLCollection es similar a un array pero no es un array real, por lo que no tiene forEach/map. Conviértela con Array.from() (o el operador de propagación [...elements]) antes de usar métodos de array.
Como la colección es viva, iterar con for (let i = 0; i < c.length; i++) mientras se eliminan elementos coincidentes puede saltarse elementos — la longitud se reduce mientras iteras. Sácale una instantánea primero con Array.from() si planeas mutar el DOM durante el bucle.
Seleccionar por nombre de etiqueta: getElementsByTagName
Selecciona todos los elementos con un nombre de etiqueta determinado y devuelve una HTMLCollection viva.
const paragraphs = document.getElementsByTagName('p');
for (let i = 0; i < paragraphs.length; i++) {
paragraphs[i].style.backgroundColor = 'yellow';
}Pasa '*' para coincidir con todos los elementos de la página. Resulta útil cuando quieres operar sobre todas las etiquetas de un tipo, como resaltar todos los párrafos.
Seleccionar por atributo name: getElementsByName
Devuelve una NodeList viva de los elementos que comparten el mismo atributo name. Es más útil para controles de formulario — por ejemplo, todos los botones de radio de un grupo:
const options = document.getElementsByName('plan');
options.forEach((radio) => {
radio.addEventListener('change', () => {
console.log('Selected plan:', radio.value);
});
});Para un manejo más profundo de formularios, consulta trabajar con formularios en el DOM.
Seleccionar con selectores CSS: querySelector
querySelector devuelve el primer elemento que coincide con cualquier selector CSS que pases, o null si nada coincide. Es el método más versátil para seleccionar un único elemento.
const element = document.querySelector('.example');
element.style.backgroundColor = 'lightblue';Como acepta la sintaxis completa de selectores CSS, puedes apuntar a elementos profundamente anidados: querySelector('nav ul li.active a') encuentra el primer enlace coincidente sin encadenar varias llamadas.
Seleccionar todas las coincidencias: querySelectorAll
Devuelve una NodeList estática de todos los elementos que coinciden con el selector. A diferencia de getElementsBy..., esta instantánea no se actualiza cuando el DOM cambia después.
const elements = document.querySelectorAll('.example');
elements.forEach((element, index) => {
element.style.backgroundColor = 'lightgreen';
element.textContent = `Element ${index + 1} highlighted!`;
});Una NodeList tiene un método forEach real, por lo que puedes iterarla directamente. Para usar map/filter, conviértela primero con Array.from(elements).
querySelectorAll devuelve una NodeList estática — no reflejará los elementos añadidos o eliminados después. getElementsByClassName y getElementsByTagName devuelven HTMLCollections vivas que sí lo hacen. Elige estática cuando quieras una instantánea estable, viva cuando quieras que la colección rastree el DOM.
Limitar la búsqueda a un elemento
Todos los métodos querySelector* y getElementsBy* también existen en elementos individuales, no solo en document. Llamarlos sobre un elemento restringe la búsqueda a los descendientes de ese elemento:
const card = document.querySelector('.card');
const title = card.querySelector('.title'); // only inside .cardLimitar el ámbito mantiene las consultas rápidas y evita coincidir accidentalmente con elementos de otras partes de la página.
Probar un elemento: matches
matches no devuelve un elemento — devuelve true/false según si un elemento dado coincide con un selector CSS. Es ideal dentro de manejadores de eventos y delegación de eventos.
const element = document.getElementById('test');
if (element.matches('.example')) {
element.style.color = 'red';
element.textContent = 'Element matches the selector!';
}Recorrer el árbol hacia arriba: closest
closest comienza en el propio elemento y sube por sus ancestros, devolviendo el más cercano que coincide con el selector (o null). Es la forma más limpia de encontrar un elemento contenedor.
const element = document.getElementById('child');
const parent = element.closest('.outer');
parent.style.border = '2px solid red';matches + closest son la base de la delegación de eventos: adjunta un oyente a un contenedor, y en el manejador usa event.target.closest('.item') para determinar qué hijo fue realmente clicado. Aprende más en manejo de eventos en el DOM.
Combinar selectores para una selección precisa
Los selectores CSS se componen, por lo que puedes ser tan específico como necesites sin código extra:
const element = document.querySelector('.example.special');
element.style.backgroundColor = 'pink';
element.textContent = 'Special element highlighted!';Aquí .example.special coincide con un elemento que tiene ambas clases. Puedes encadenar combinadores (>, espacio descendiente, +, ~), selectores de atributo (input[type="email"]) y pseudoclases (li:first-child).
¿Qué método debo usar?
| Método | Devuelve | ¿Vivo? | Mejor para |
|---|---|---|---|
getElementById | elemento único / null | n/a | un elemento con un ID único conocido |
getElementsByClassName | HTMLCollection | vivo | todos los elementos de una clase, rastreando el DOM |
getElementsByTagName | HTMLCollection | vivo | todos los elementos de una etiqueta |
getElementsByName | NodeList | vivo | controles de formulario con el mismo name |
querySelector | primera coincidencia / null | n/a | primer elemento que coincida con cualquier selector CSS |
querySelectorAll | NodeList | estática | una instantánea estable de todas las coincidencias |
matches | boolean | n/a | comprobar si un elemento encaja en un selector |
closest | ancestro más cercano / null | n/a | encontrar un elemento contenedor |
Reglas generales:
- Opta por
querySelector/querySelectorAllpor defecto — una API consistente con toda la potencia de CSS. - Usa
getElementByIdcuando tengas un ID único y quieras la búsqueda más rápida posible. - Usa una colección viva (
getElementsBy...) solo cuando específicamente quieras que rastree los cambios del DOM; de lo contrario, prefierequerySelectorAllestático.
Errores comunes
- Resultados
null.getElementById,querySelectoryclosestdevuelvennullcuando no hay coincidencia. Comprueba siempre antes de usar el resultado. - Ejecutar antes de que exista el DOM. Si tu script se ejecuta en
<head>antes de que los elementos sean analizados, las selecciones no devuelven nada. Pon los scripts al final de<body>, usadefer, o espera aDOMContentLoaded. - Las colecciones no son arrays.
HTMLCollectionno tieneforEach.NodeListtieneforEachpero nomap/filter. Convierte conArray.from()si tienes dudas.
Conclusión
Seleccionar elementos es el punto de entrada para cualquier tarea del DOM. Para la mayor parte del código, querySelector y querySelectorAll te dan una API flexible y potenciada por CSS; getElementById sigue siendo la opción más rápida para IDs únicos; y matches / closest potencian una delegación de eventos limpia. Una vez que puedas seleccionar elementos de forma fiable, continúa con manipulación del DOM y recorrer el DOM.
Nota de rendimiento: Todos estos métodos son lo suficientemente rápidos para páginas típicas. El coste real viene de ejecutarlos repetidamente en bucles cerrados — guarda una selección en una variable en lugar de volver a consultar. Las NodeLists estáticas de querySelectorAll evitan el seguimiento de reflujo que mantiene actualizadas las HTMLCollections vivas.