jQuery / Método / .html() - Ler ou substituir o conteúdo dos elementos

No jQuery, .html() sem argumento lê a string HTML interna do primeiro elemento selecionado. Passar uma string substitui o conteúdo de todos os selecionados, mantendo os elementos externos. Para exibir entrada como caracteres, use .text() em vez de interpretá-la como HTML com .html().

Leitura, escrita, text e val

A API .html() devolve string ao ler e objeto jQuery ao escrever. HTML interno é a representação do modelo de objetos do documento, DOM, produzida pelo navegador; espaços e tags não precisam reproduzir exatamente o arquivo original.

Chamada Resultado ou operação Vários elementos selecionados
.html() String HTML interna com tags Lê somente o primeiro
.html(markup) Substitui conteúdo como HTML Aplica a todos
.text() Texto sem marcação Combina o texto de todos
.text(value) Mostra string como texto Substitui conteúdo de todos
.val() Valor atual do controle Lê o primeiro controle

.text() não interpreta a string como tags. Valores atuais de input e textarea não são HTML interno: use .val(). O getter .html() em seleção vazia devolve undefined. Confira a existência do alvo antes de chamar métodos de string no resultado.

Exemplo completo de HTML e texto

Salve todo o código em UTF-8 como html-demo.html e abra no navegador. É preciso internet para carregar o arquivo oficial do jQuery 4.0.0 pela rede de distribuição de conteúdo, CDN, sem instalar pacotes. Leitura, substituição, entrada, Reset e exemplos do Console foram executados com 3.7.1 e 4.0.0.

A primeira caixa contém Alpha em strong; a segunda, Beta em em. O relatório também usa .text(), então o HTML lido aparece como string e não é interpretado nele.

<!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>

Inicialmente o HTML vem apenas de Alpha e o texto combina as duas caixas:

first html=<strong>Alpha</strong>
combined text=AlphaBeta
boxes=2
  1. Read lê novamente o estado. first html exclui o div externo.
  2. Replace with fixed HTML troca os dois conteúdos por botões New. Continuam duas caixas e combined text é NewNew.
  3. Cada New aumenta Delegated clicks. Substituir novamente continua dando um incremento por clique.
  4. Show message as text mostra <b>Hello</b> com os caracteres das tags nas duas caixas, sem criar b.
  5. Edite Message e repita. Esse caminho lê com .val() e passa o valor a .text().
  6. Reset restaura o HTML guardado de cada caixa, mensagem e zero cliques. Não registra novamente o manipulador delegado externo.

Não inserir entrada não confiável como HTML

Métodos que interpretam HTML podem receber atributos executáveis e scripts além de tags comuns. Passar entrada não confiável diretamente a .html() pode introduzir cross-site scripting, XSS. O botão de substituição usa apenas uma string fixa do desenvolvedor; Message é tratado como texto.

Receber conteúdo do servidor não o torna automaticamente confiável. Para comentários, buscas e dados externos que devem aparecer como caracteres, use .text(). Se HTML externo formatado for necessário, planeje elementos/atributos permitidos e uma sanitização estabelecida separadamente. Substituir strings ou retirar algumas tags não é defesa completa.

Eventos e dados dos filhos substituídos

.html(newHtml) substitui todo o conteúdo, em vez de acrescentar. Filhos anteriores, dados e manipuladores diretos jQuery são limpos. Execute este trecho completo no Console: ele cria um contêiner temporário e o remove no final.

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

O botão novo não tem o manipulador direto antigo, então direct é zero. O pai permanece e seu manipulador delegado .on() trata o novo .child, dando delegated um. Mesmo com $old, o nó anterior está fora do documento e token é undefined. Substituir o próprio pai não preservaria seu manipulador delegado.

Função para conteúdo específico por elemento

.html(function(index, oldHtml)) recebe o índice a partir de zero e HTML anterior, retornando uma nova string. Use oldHtml para o conteúdo anterior dentro do callback. Este exemplo do Console acrescenta spans numerados ao HTML A/B fixado pelo desenvolvedor.

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 não se torna seguro automaticamente. Use conteúdo conhecido como aqui, sem expandir o padrão concatenando entradas externas. Se nada mudar, confira escopo da seleção, alvo existente, estrutura interna desejada, carregamento em Network e erros no Console. Se a intenção era acrescentar, veja se substituir tudo com .html() é adequado.