Ir al contenido principal

Modificación de contenido y atributos

Introducción

Una vez que hemos aprendido a seleccionar elementos del DOM, el siguiente paso natural es modificarlos. La modificación dinámica del contenido y los atributos de los elementos HTML es lo que hace que las páginas web sean interactivas y respondan a las acciones del usuario. En este artículo, exploraremos las diferentes formas de modificar el texto, el HTML, los atributos y las clases CSS de los elementos seleccionados. Estas técnicas son fundamentales para crear experiencias web dinámicas y atractivas.

Modificación de contenido de texto

JavaScript nos ofrece varias formas de manipular el contenido textual de los elementos. Las dos propiedades principales son textContent e innerText:

La propiedad textContent

Esta propiedad permite acceder o modificar el contenido de texto de un elemento, incluyendo todo el texto contenido en el elemento y sus descendientes:

// HTML: <div id="mensaje">Hola <span>mundo</span></div>

const mensaje = document.getElementById("mensaje");

// Leer el contenido de texto
console.log(mensaje.textContent); // "Hola mundo"

// Modificar el contenido de texto
mensaje.textContent = "Nuevo texto";
// Ahora el HTML es: <div id="mensaje">Nuevo texto</div>

Características importantes:

  • Devuelve todo el texto, incluyendo espacios y saltos de línea
  • Ignora el marcado HTML (lo trata como texto plano)
  • Es más eficiente que innerHTML

La propiedad innerText

Similar a textContent, pero tiene en cuenta la presentación CSS:

// HTML: 
// <div id="ejemplo">
//   Texto visible
//   <span style="display: none">Texto oculto</span>
// </div>

const ejemplo = document.getElementById("ejemplo");

console.log(ejemplo.textContent); // "Texto visible Texto oculto"
console.log(ejemplo.innerText); // "Texto visible"

Diferencias con textContent:

  • innerText solo devuelve el texto visible (respeta CSS)
  • innerText respeta los saltos de línea visibles
  • innerText es más lento porque necesita calcular estilos

Propiedades innerHTML vs textContent

La propiedad innerHTML permite trabajar con el contenido HTML de un elemento:

// HTML: <div id="contenedor">Texto <b>importante</b></div>

const contenedor = document.getElementById("contenedor");

// Leer el HTML interno
console.log(contenedor.innerHTML); // "Texto <b>importante</b>"

// Modificar el HTML interno
contenedor.innerHTML = "Texto <i>actualizado</i>";
// Ahora el HTML es: <div id="contenedor">Texto <i>actualizado</i></div>

Comparación de usos:

const elemento = document.getElementById("ejemplo");

// Con textContent (trata todo como texto)
elemento.textContent = "<b>Texto en negrita</b>";
// Resultado: El usuario ve literalmente: "<b>Texto en negrita</b>"

// Con innerHTML (interpreta el HTML)
elemento.innerHTML = "<b>Texto en negrita</b>";
// Resultado: El usuario ve: "Texto en negrita" (en negrita)

Consideraciones de seguridad con innerHTML

Es importante mencionar que innerHTML puede representar un riesgo de seguridad si se utiliza con contenido no confiable:

// PELIGROSO: Nunca uses innerHTML con datos proporcionados por usuarios
const comentarioUsuario = "<script>alert('código malicioso')</script>";
elemento.innerHTML = comentarioUsuario; // Potencial ataque XSS

Para contenido generado por usuarios, es más seguro usar textContent.

Manipulación de atributos HTML

Atributos estándar

Para trabajar con atributos HTML estándar, podemos usar varios métodos:

const enlace = document.getElementById("mi-enlace");

// Obtener un atributo
const url = enlace.getAttribute("href");
console.log(url); // Por ejemplo: "https://ejemplo.com"

// Establecer un atributo
enlace.setAttribute("href", "https://nueva-url.com");
enlace.setAttribute("target", "_blank");

// Comprobar si existe un atributo
if (enlace.hasAttribute("rel")) {
    console.log("El enlace tiene un atributo rel");
}

// Eliminar un atributo
enlace.removeAttribute("target");

Acceso directo a atributos comunes

Muchos atributos estándar tienen acceso directo como propiedades:

const imagen = document.getElementById("mi-imagen");

// Acceso directo a atributos comunes
imagen.src = "nueva-imagen.jpg";
imagen.alt = "Descripción de la imagen";

const formulario = document.getElementById("mi-formulario");
formulario.action = "/procesar";
formulario.method = "post";

Esta forma es más concisa y generalmente preferible para atributos estándar.

Manipulación de atributos data-*

Los atributos personalizados data-* son muy útiles para almacenar información adicional en elementos HTML:

// HTML: <div id="producto" data-id="123" data-categoria="electronica">iPhone</div>

const producto = document.getElementById("producto");

// Acceder a atributos data-*
const id = producto.dataset.id; // "123"
const categoria = producto.dataset.categoria; // "electronica"

// Modificar atributos data-*
producto.dataset.precio = "999";
producto.dataset.disponible = "true";

// Comprobar si existe un atributo data-*
if ("precio" in producto.dataset) {
    console.log("El producto tiene precio definido");
}

// Eliminar un atributo data-*
delete producto.dataset.disponible;

Los atributos data-* son perfectos para almacenar información que necesitamos en JavaScript sin afectar la presentación.

Modificación de clases CSS

La manipulación de clases CSS es una de las formas más comunes de modificar la apariencia de los elementos.

La propiedad className

La forma tradicional de modificar clases es mediante la propiedad className:

const elemento = document.getElementById("mi-elemento");

// Leer las clases actuales
console.log(elemento.className); // Por ejemplo: "boton primario"

// Sobrescribir todas las clases
elemento.className = "boton secundario";

Sin embargo, este enfoque sobrescribe todas las clases existentes, lo que no siempre es deseable.

El objeto classList

El objeto classList proporciona métodos más precisos para manejar clases:

const boton = document.getElementById("mi-boton");

// Añadir una clase
boton.classList.add("destacado");

// Eliminar una clase
boton.classList.remove("inactivo");

// Alternar una clase (la añade si no existe, la elimina si existe)
boton.classList.toggle("seleccionado");

// Comprobar si tiene una clase específica
if (boton.classList.contains("primario")) {
    console.log("Es un botón primario");
}

// Reemplazar una clase por otra
boton.classList.replace("error", "exito");

El objeto classList es mucho más versátil y es la forma recomendada de trabajar con clases en JavaScript moderno.

Manipulación de estilos directos

Aunque generalmente es mejor usar clases CSS para controlar la apariencia, a veces necesitamos modificar estilos directamente mediante la propiedad style:

const caja = document.getElementById("mi-caja");

// Establecer estilos individuales
caja.style.backgroundColor = "skyblue";
caja.style.width = "200px";
caja.style.padding = "20px";
caja.style.borderRadius = "10px";

// Notar que las propiedades CSS con guiones se convierten a camelCase
// Por ejemplo: background-color -> backgroundColor

// Leer un estilo inline específico
console.log(caja.style.backgroundColor); // "skyblue"

Importante: la propiedad style solo accede y modifica los estilos inline (definidos directamente en el atributo style del elemento HTML). No refleja los estilos definidos en hojas de estilo CSS.

Obtener estilos computados

Para obtener los estilos reales aplicados (de cualquier origen):

const elemento = document.getElementById("ejemplo");
const estilos = window.getComputedStyle(elemento);

const colorActual = estilos.getPropertyValue("color");
const tamanoFuente = estilos.fontSize; // También se puede acceder con notación de punto

console.log(`Color: ${colorActual}, Tamaño: ${tamanoFuente}`);

Modificación de valores de formularios

Los elementos de formulario tienen propiedades específicas para acceder y modificar sus valores:

// Input de texto
const nombreInput = document.getElementById("nombre");
nombreInput.value = "Juan Pérez";

// Checkbox
const aceptaTerminos = document.getElementById("terminos");
aceptaTerminos.checked = true;

// Radio button
const opcionHombre = document.getElementById("genero-hombre");
opcionHombre.checked = true;

// Select
const selectPais = document.getElementById("pais");
selectPais.value = "es"; // Selecciona la opción con value="es"

// Select (alternativa)
selectPais.selectedIndex = 2; // Selecciona la tercera opción (índice 2)

// Textarea
const comentarios = document.getElementById("comentarios");
comentarios.value = "Nuevo comentario";

// Deshabilitar un campo
nombreInput.disabled = true;

// Hacer un campo de solo lectura
comentarios.readOnly = true;

Buenas prácticas de modificación

  1. Minimiza las manipulaciones del DOM: Cada modificación puede causar reflow/repaint.
// Mal (causa múltiples reflow)
for (let i = 0; i < 100; i++) {
    contenedor.innerHTML += `<div>${i}</div>`;
}

// Bien (una sola modificación al DOM)
let contenidoHTML = "";
for (let i = 0; i < 100; i++) {
    contenidoHTML += `<div>${i}</div>`;
}
contenedor.innerHTML = contenidoHTML;
  1. Usa classList en lugar de className cuando solo necesites modificar clases específicas.

  2. Preferir cambios de clase sobre estilos inline: Es más mantenible y eficiente.

// Menos recomendado
elemento.style.backgroundColor = "red";
elemento.style.fontWeight = "bold";

// Más recomendado
elemento.classList.add("error-destacado");
// Y definir esos estilos en CSS: .error-destacado { background-color: red; font-weight: bold; }
  1. Evita innerHTML con contenido no confiable: Usa alternativas más seguras:
// Mejor alternativa a innerHTML para contenido dinámico
const nuevoElemento = document.createElement("div");
nuevoElemento.textContent = contenidoUsuario;
contenedor.appendChild(nuevoElemento);

Ejemplos prácticos

Ejemplo 1: Sistema de notificaciones

function mostrarNotificacion(mensaje, tipo) {
    const notificacion = document.getElementById("notificacion");
    
    // Establecer contenido
    notificacion.textContent = mensaje;
    
    // Resetear clases y añadir la que corresponda al tipo
    notificacion.className = "notificacion";
    notificacion.classList.add(tipo); // tipo puede ser "exito", "error", "aviso"
    
    // Hacer visible
    notificacion.style.display = "block";
    
    // Ocultar automáticamente después de 3 segundos
    setTimeout(() => {
        notificacion.style.display = "none";
    }, 3000);
}

// Uso
mostrarNotificacion("Datos guardados correctamente", "exito");

Ejemplo 2: Cambio de tema (claro/oscuro)

function cambiarTema() {
    const body = document.body;
    const botonTema = document.getElementById("boton-tema");
    
    // Alternar clase en el body
    body.classList.toggle("tema-oscuro");
    
    // Actualizar texto del botón según el tema actual
    if (body.classList.contains("tema-oscuro")) {
        botonTema.textContent = "Cambiar a tema claro";
        botonTema.setAttribute("aria-pressed", "true");
    } else {
        botonTema.textContent = "Cambiar a tema oscuro";
        botonTema.setAttribute("aria-pressed", "false");
    }
    
    // Guardar preferencia en localStorage
    const temaActual = body.classList.contains("tema-oscuro") ? "oscuro" : "claro";
    localStorage.setItem("tema-preferido", temaActual);
}

Ejemplo 3: Validación de formulario en tiempo real

const campoEmail = document.getElementById("email");

campoEmail.addEventListener("blur", function() {
    // Expresión regular simple para validar email
    const esValido = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(this.value);
    
    if (!esValido && this.value !== "") {
        // Marcar como inválido
        this.classList.add("invalid");
        
        // Añadir mensaje de error si no existe
        if (!this.nextElementSibling || !this.nextElementSibling.classList.contains("error-mensaje")) {
            const mensajeError = document.createElement("div");
            mensajeError.textContent = "Por favor, introduce un email válido";
            mensajeError.className = "error-mensaje";
            this.insertAdjacentElement("afterend", mensajeError);
        }
    } else {
        // Quitar marca de inválido
        this.classList.remove("invalid");
        
        // Eliminar mensaje de error si existe
        if (this.nextElementSibling && this.nextElementSibling.classList.contains("error-mensaje")) {
            this.nextElementSibling.remove();
        }
    }
});

Resumen

En este artículo hemos explorado las diferentes formas de modificar elementos del DOM: cambiar su contenido de texto, modificar su HTML interno, manipular atributos, gestionar clases CSS y modificar estilos directamente. También hemos visto cómo trabajar con elementos de formulario y algunas buenas prácticas para realizar estas modificaciones de manera eficiente.

Estas técnicas son fundamentales para crear interacciones dinámicas y responder a las acciones del usuario en páginas web. En el próximo artículo, aprenderemos cómo crear y eliminar elementos del DOM, lo que nos permitirá modificar la estructura misma de nuestra página de forma dinámica.