jQuery / Método / .html() - Leer o reemplazar el contenido de elementos

En jQuery, .html() sin argumentos lee la cadena HTML interna del primer elemento seleccionado. Pasar una cadena reemplaza el contenido de todos los seleccionados, manteniendo sus elementos exteriores. Para mostrar entradas como caracteres, usa .text() en lugar de interpretarlas como HTML con .html().

Lectura, escritura, text y val

La API .html() devuelve una cadena al leer y un objeto jQuery al escribir. El HTML interno es la representación del modelo de objetos del documento, DOM, producida por el navegador; no tiene por qué reproducir exactamente espacios y etiquetas del archivo original.

Llamada Resultado u operación Varios elementos seleccionados
.html() Cadena HTML interna con etiquetas Lee solo el primero
.html(markup) Reemplaza contenido como HTML Se aplica a todos
.text() Texto sin marcado Combina el texto de todos
.text(value) Muestra la cadena como texto Reemplaza contenido de todos
.val() Valor actual del control Lee el primero

.text() no interpreta la cadena como etiquetas. Los valores actuales de input y textarea no son HTML interno: usa .val(). El getter .html() sobre selección vacía devuelve undefined. Comprueba que existe un objetivo antes de llamar métodos de cadena sobre el resultado.

Ejemplo completo de HTML y texto

Guarda todo el código en UTF-8 como html-demo.html y ábrelo en el navegador. Necesitas internet para cargar el archivo oficial de jQuery 4.0.0 desde su red de distribución de contenidos, CDN, sin instalar paquetes. Lectura, reemplazo, entrada, Reset y ejemplos Console se ejecutaron con 3.7.1 y 4.0.0.

La primera caja contiene Alpha en strong; la segunda Beta en em. El informe también usa .text(), así que el HTML leído se ve como una cadena y no se interpreta en él.

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Read and replace HTML contents</title>
  <script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
  <style>
    body { font: 16px/1.6 sans-serif; max-width: 760px; margin: 24px auto; padding: 16px; }
    button, input { font: inherit; margin: 4px; max-width: 100%; }
    .box { border: 2px solid teal; padding: 16px; margin: 12px 0; }
    pre { white-space: pre-wrap; overflow-wrap: anywhere; }
  </style>
</head>
<body>
  <h1>HTML markup versus plain text</h1>
  <button type="button" id="read">Read</button>
  <button type="button" id="replace">Replace with fixed HTML</button>
  <label>Message <input id="message" value="&lt;b&gt;Hello&lt;/b&gt;"></label>
  <button type="button" id="plain">Show message as text</button>
  <button type="button" id="reset">Reset</button>
  <div id="examples">
    <div class="box"><strong>Alpha</strong></div>
    <div class="box"><em>Beta</em></div>
  </div>
  <p>Delegated clicks: <span id="clicks">0</span></p>
  <pre id="result" aria-live="polite"></pre>
  <script>
    $(function () {
      const $boxes = $(".box");
      const initial = $boxes.get().map(node => node.innerHTML);
      let clicks = 0;
      function report() {
        $("#result").text(`first html=${$boxes.html()}\ncombined text=${$boxes.text()}\nboxes=${$boxes.length}`);
      }
      $("#read").on("click", report);
      $("#replace").on("click", function () {
        $boxes.html('<button type="button" class="child">New</button>');
        report();
      });
      $("#plain").on("click", function () {
        $boxes.text($("#message").val());
        report();
      });
      $("#examples").on("click.htmlLesson", ".child", function () {
        clicks++;
        $("#clicks").text(clicks);
      });
      $("#reset").on("click", function () {
        $boxes.html(function (index) { return initial[index]; });
        $("#message").val("<b>Hello</b>");
        clicks = 0;
        $("#clicks").text(clicks);
        report();
      });
      report();
    });
  </script>
</body>
</html>

Al inicio el HTML procede solo de Alpha y el texto combina ambas cajas:

first html=<strong>Alpha</strong>
combined text=AlphaBeta
boxes=2
  1. Read relee el estado. first html excluye el div exterior.
  2. Replace with fixed HTML cambia ambos contenidos por botones New. Siguen existiendo dos cajas y combined text es NewNew.
  3. Cada New aumenta Delegated clicks. Reemplazar otra vez sigue dando un incremento por clic.
  4. Show message as text muestra <b>Hello</b> con caracteres de etiquetas en ambas cajas, sin crear b.
  5. Edita Message y repite. Este recorrido lee con .val() y pasa el valor a .text().
  6. Reset restaura HTML guardado de cada caja, mensaje y cero clics. No registra otra vez el manejador delegado exterior.

No insertar entradas no fiables como HTML

Los métodos que interpretan HTML pueden aceptar atributos ejecutables o scripts además de etiquetas normales. Pasar una entrada no fiable directamente a .html() puede introducir cross-site scripting, XSS. El botón de reemplazo utiliza solo una cadena fija del desarrollador; Message se trata como texto.

Recibir contenido de un servidor no garantiza confianza. Para comentarios, búsquedas o datos externos que deben verse como caracteres, usa .text(). Si hace falta HTML enriquecido externo, diseña elementos/atributos permitidos y una limpieza validada por separado. Sustituir cadenas o quitar unas etiquetas no es una defensa completa.

Eventos y datos de hijos reemplazados

.html(newHtml) reemplaza todo el contenido en lugar de añadir al final. Se limpian los hijos anteriores, sus datos y manejadores directos jQuery. Ejecuta este fragmento completo en Console: crea un contenedor temporal y lo elimina al terminar.

const $host = $('<div><button class="child">Old</button></div>').appendTo("body");
const $old = $host.find("button");
let direct = 0;
let delegated = 0;
$old.data("token", "stored").on("click", () => direct++);
$host.on("click", ".child", () => delegated++);
$host.html('<button class="child">New</button>');
$host.find("button").trigger("click");
console.log(`direct=${direct} | delegated=${delegated}`);
console.log(`old attached=${document.contains($old[0])} | old data=${typeof $old.data("token")}`);
$host.remove();
direct=0 | delegated=1
old attached=false | old data=undefined

El botón nuevo no tiene el manejador directo anterior, por eso direct es cero. El padre permanece y su manejador delegado .on() trata el nuevo .child, con delegated uno. Aunque exista $old, el nodo anterior está fuera del documento y token es undefined. Reemplazar el propio padre no conservaría su manejador delegado.

Función para contenido específico por elemento

.html(function(index, oldHtml)) recibe el índice desde cero y HTML anterior y devuelve una cadena nueva. Usa oldHtml para acceder al contenido anterior dentro del callback. Este ejemplo Console añade spans numerados al marcado A/B fijado por el desarrollador.

const $boxes = $("<div><b>A</b></div><div><i>B</i></div>");
$boxes.html(function (index, oldHtml) {
  return oldHtml + "<span>" + (index + 1) + "</span>";
});
console.log($boxes.get().map(node => node.innerHTML).join(" | "));
console.log(`empty getter=${typeof $().html()}`);
$boxes.remove();
<b>A</b><span>1</span> | <i>B</i><span>2</span>
empty getter=undefined

oldHtml no se vuelve seguro automáticamente. Usa contenido conocido como aquí, sin ampliar el patrón concatenando entradas externas. Si nada cambia, revisa ámbito de selección, objetivo existente, estructura interna deseada, carga en Network y errores Console. Si querías añadir contenido, reconsidera si reemplazarlo todo con .html() es lo adecuado.