Atualizações parciais declarativas

Publicado em: 19 de maio de 2026

A Web já superou há muito tempo o meio estático e orientado a documentos que era no início. Os apps da Web modernos e avançados são usados por todos por vários motivos, desde comunicação, compras, consumo de conteúdo avançado até o gerenciamento das nossas vidas complexas.

O HTML, apesar de todos os avanços, ainda é entregue em ordem, de cima para baixo, com pouca consideração sobre quando o conteúdo está pronto ou quando o usuário o consome. O CSS permite mudar a ordem do conteúdo, mas geralmente com efeitos colaterais significativos na acessibilidade. O JavaScript permite manipular o DOM por várias APIs para se livrar um pouco disso, mas geralmente elas exigem sintaxe detalhada ou construção de árvores DOM para se conectar ao HTML.

O desempenho é extremamente importante para a Web, dada a natureza cliente-servidor do meio. No entanto, muitas vezes são feitas escolhas abaixo do ideal para contornar essa natureza em ordem do HTML, o que diminui o desempenho. Isso inclui esperar até que a página inteira esteja pronta ou usar uma estrutura pesada para entregar componentes de maneira assíncrona. A popularidade dos frameworks JavaScript mostra que os desenvolvedores da Web preferem um modelo baseado em componentes em vez do modelo mental rígido de documentos das origens da Web.

A equipe do Chrome está considerando esse problema e desenvolvendo novas adições à plataforma da Web sob o nome de Atualizações parciais declarativas.

Dois novos conjuntos de APIs facilitam a entrega de HTML de maneira menos linear, seja fora de ordem no próprio documento HTML ou por maneiras mais fáceis de inserir HTML dinamicamente em documentos existentes usando novas APIs JavaScript. Eles estão prontos para testes de desenvolvedores no Chrome 148 usando a flag chrome://flags/#enable-experimental-web-platform-features. Os polyfills também estão disponíveis para que você possa usar essas novas APIs imediatamente, mesmo em navegadores que ainda não as oferecem suporte.

Essas adições à plataforma da Web estão sendo padronizadas com feedback positivo de outros fornecedores de navegadores e canais de padronização. Os padrões relevantes estão sendo atualizados para incluir essas novas APIs.

Streaming fora de ordem

O primeiro conjunto de mudanças são novas APIs de streaming fora de ordem usando o elemento HTML <template> e marcadores de posição de instruções de processamento. Exemplo:

<div>
  <?marker name="placeholder">
</div>

...

<template for="placeholder">
  Here is some <em>HTML content</em>!
</template>

As instruções de processamento existem em XML há muito tempo, mas são tratadas como comentários em HTML e ignoradas. Essa nova API muda isso e traz instruções de processamento para HTML. Quando o navegador vê as instruções de processamento <?marker name="placeholder">, ele não faz nada imediatamente, assim como antes, mas elas podem ser referenciadas mais tarde.

O elemento <template> procura as instruções de processamento correspondentes com um atributo name e substitui o conteúdo. Nesse caso, depois de ser analisado, o DOM fica assim:

<div>
  Here is some <em>HTML content</em>!
</div>

Além do atributo <?marker> para substituições, também há marcadores de intervalo <?start> e <?end> que permitem mostrar conteúdo de marcador de posição temporário antes que o modelo seja processado:

<div>
  <?start name="another-placeholder">
  Loading…
  <?end>
</div>

...

<template for="another-placeholder">
  Here is some <em>HTML content</em>!
</template>

Nesse caso, Loading… aparece até que o <template> seja visto e, em seguida, é substituído pelo novo conteúdo.

Também é possível incluir instruções de processamento em modelos para permitir várias atualizações:

<ul id="results">
  <?start name="results">
  Loading…
  <?end>
</ul>

...

<template for="results">
  <li>Result One</li>
  <?marker name="results">
</template>
...

<template for="results">
  <li>Result Two</li>
  <?marker name="results">
</template>
...

Isso resulta no seguinte HTML após a análise:

<ul id="results">
  <li>Result One</li>
  <li>Result Two</li>
  <?marker name="results">
</ul>

Com a instrução de processamento final no final, caso mais <template for="results"> sejam adicionados ao documento depois.

Demonstração

Neste vídeo, um aplicativo básico de álbum de fotos é implementado com HTML de streaming:

Demonstração de álbum de fotos implementada com streaming fora de ordem (fonte)

O status e as fotos são transmitidos para o HTML após o layout inicial.

Casos de uso

Há muitos casos de uso para esse patch HTML fora de ordem quando combinado com o streaming HTML:

  • Arquitetura de ilha. Um padrão comum popularizado por frameworks como o Astro é a arquitetura de ilha, em que os componentes são hidratados de forma independente em cima do HTML estático. A API <template for> permite que o conteúdo estático seja processado de maneira semelhante diretamente em HTML. Os frameworks JavaScript também podem usar isso para ilhas mais interativas ou para processar componentes.
  • Entregue o conteúdo quando ele estiver pronto. Graças a essa arquitetura de ilha, o conteúdo pode ser transmitido quando estiver pronto, em vez de ser retido para conteúdo que requer processamento extra, por exemplo, uma pesquisa em banco de dados. Embora muitas plataformas permitam o streaming de HTML, a natureza ordenada do HTML significa que o conteúdo geralmente é retido ou recorrendo a manipulações complexas do DOM JavaScript. Agora você pode entregar o conteúdo estático enquanto espera e, em seguida, inserir o conteúdo mais caro no final do fluxo HTML.
  • O HTML pode ser entregue na ordem ideal para o desempenho do carregamento de página. Você pode mudar o pedido mesmo quando ele estiver pronto. Por exemplo, os mega menus são um recurso de navegação comum que contém muito HTML que o usuário não vê até que a página se torne interativa. Essa grande parte do HTML pode ser entregue mais tarde no documento HTML para priorizar o HTML mais importante necessário para o carregamento de página inicial. A ordem não é mais uma barreira com HTML.

Esses são apenas alguns casos de uso, e é interessante ver para que os desenvolvedores vão usar essa nova API.

Restrições e sutilezas

A API inclui algumas restrições e sutilezas que precisam ser consideradas:

  • Por motivos de segurança, <template for> só pode atualizar instruções de processamento no mesmo elemento pai. Adicionar <template for> diretamente ao elemento <body> dá acesso a todo o documento (incluindo o <head>).
  • A instrução de processamento <?end> é opcional. Se ela estiver ausente, o conteúdo entre o elemento <?start> e o fim do elemento contido será substituído.
  • Mover instruções de processamento depois que um <template for> começa a ser transmitido também pode ter consequências inesperadas, com o novo conteúdo continuando a ser transmitido para o local antigo.
  • Ao inserir <template for> dinamicamente com um método como setHTML ou innerHTML, o "pai" do modelo quando ele é analisado é um fragmento de documento intermediário. Isso significa que a inserção de HTML usando esses métodos não pode modificar o DOM atual, e o patch acontece "no lugar" dentro do fragmento. No entanto, ao fazer streaming usando métodos como streamHTMLUnsafe (que vamos abordar em breve), não há um fragmento intermediário. Assim, os modelos podem substituir o conteúdo atual.

Possíveis adições futuras

Algumas possíveis adições futuras em consideração incluem:

  • Inclusões do lado do cliente Por exemplo, <template for="footer" patchsrc="/partials/footer.html">.
  • Agrupamento em lote. No lado do cliente, as inclusões de fragmentos também podem ser estendidas para processar o agrupamento em lotes e garantir que várias atualizações ocorram ao mesmo tempo.
  • Evitar a substituição de conteúdo que não vai mudar. Isso pode ser feito com um número de revisão ou controle de versão do conteúdo. Isso permite que o estado seja mantido entre mudanças de rota ou outras atualizações, em vez de redefinir o conteúdo.
  • Higienização durante a aplicação de patch. Por exemplo, <template for=icon safe><svg id="from-untrusted-source">...</svg></template>

Polyfill

A equipe do Chrome lançou um template-for-polyfill disponível no npm para que os sites usem essa nova funcionalidade imediatamente, mesmo antes de ela ser lançada em outros navegadores.

algumas limitações, já que não é possível atualizar diretamente os analisadores HTML do navegador, mas os casos de uso mais comuns são cobertos. Os sites ainda precisam ser testados em outros navegadores.

Métodos de inserção e streaming de HTML renovados

Nem todo conteúdo pode ser entregue em HTML. Uma segunda parte do trabalho do Chrome nessa área envolve facilitar a atualização de conteúdo usando JavaScript.

Já existem várias maneiras de injetar dinamicamente HTML em um documento usando JavaScript:

  • setHTML
  • setHTMLUnsafe
  • Definidores de innerHTML e outerHTML
  • createContextualFragment
  • insertAdjacentHTML

No entanto, todos funcionam de maneiras ligeiramente diferentes, com sutilezas e diferenças que os desenvolvedores nem sempre consideram:

  • O novo conteúdo substitui ou é anexado?
  • Eles higienizam HTML potencialmente perigoso, por exemplo, escapando tags <script>?
  • Caso contrário, <script> deve ser executado?
  • Como eles funcionam com TrustedTypes?

Poucos desenvolvedores podem analisar essas APIs e responder a essas perguntas com confiança para cada uma delas.

Uma grande limitação é que eles só podem ser usados para um conjunto completo de HTML conhecido antecipadamente, quando há chamadas para permitir o streaming de HTML. Na prática, isso significa que você precisa baixar todo o conteúdo antes de inserir, quando um dos pontos fortes do HTML é a capacidade de transmitir conteúdo imediatamente. Isso pode ser contornado de forma limitada dividindo payloads ou usando métodos hacky e descontinuados, como document.write, mas eles introduzem problemas próprios.

Um novo conjunto de APIs estáticas e de streaming

O Chrome propôs um conjunto de novas APIs e extensões para os setHTML e setHTMLUnsafe atuais que limpam isso, além de introduzir a funcionalidade de streaming:

Há métodos para definir ou substituir, além de métodos para inserir conteúdo antes ou depois do HTML atual. Cada método tem equivalentes de stream:

Ação Estático Streaming
Definir o conteúdo HTML do elemento setHTML(html, options); streamHTML(options);
Substitua todo o elemento por este HTML replaceWithHTML(html, options); streamReplaceWithHTML(options);
Adicionar o HTML antes do elemento beforeHTML(html, options); streamBeforeHTML(options);
Adicione o HTML como o primeiro filho do elemento prependHTML(html, options); streamPrependHTML(options);
Adicione o HTML como o último filho do elemento appendHTML(html, options); streamAppendHTML(options);
Adicione o HTML depois do elemento afterHTML(html, options); streamAfterHTML(options);
Os novos métodos de inserção e streaming

Também há versões do Unsafe, que vamos abordar em breve. Embora pareça haver muitos deles (principalmente quando você adiciona os equivalentes Unsafe), a convenção de nomenclatura consistente torna mais óbvio o que cada um faz em comparação com os métodos não relacionados mencionados anteriormente.

As versões estáticas usam um novo HTML como argumento de string DOM, além de opções opcionais:

const newHTML = "<p>This is a new paragraph</p>";
const contentElement = document.querySelector('#content-to-update');

contentElement.setHTML(newHTML);

As versões de streaming funcionam com a API Streams, como com um getWriter():

const contentElement = document.querySelector('#content-to-update');
const writer = contentElement.streamHTMLUnsafe().getWriter();

// Example stream of updating content
while (true) {
 await writer.write(`<p>${++i}</p>`);
 await new Promise((resolve) => setTimeout(resolve, 1000));
}

writer.close();

Ou, alternativamente, de uma resposta de busca, com cadeias de pipes:

const contentElement = document.querySelector('#content-to-update');

const response = await fetch('/api/content.html');

response.body
  .pipeThrough(new TextDecoderStream())
  .pipeTo(contentElement.streamHTMLUnsafe());

Também planejamos adicionar um método de conveniência em que você pode transmitir diretamente sem precisar da etapa intermediária TextDecoderStream().

O argumento options permite especificar um sanitizer personalizado, que tem como padrão default, ou seja, a configuração padrão do higienizador. Ele é usado assim:

const newHTML = "<p>This is a new paragraph</p>";
const contentElement = document.querySelector('#content-to-update');

// Only allows basic formatting
const basicFormattingSanitzer = new Sanitizer({ elements: ["em", "i", "b", "strong"] });

contentElement.setHTML(newHTML, {sanitizer: basicFormattingSanitzer});

Métodos "inseguros"

Também há versões "inseguras" de cada uma das APIs:

Ação Estático Streaming
Definir o conteúdo HTML do elemento setHTMLUnsafe(html,options); streamHTMLUnsafe(options);
Substitua todo o elemento por este HTML replaceWithHTMLUnsafe(html, options); streamReplaceWithHTMLUnsafe(options);
Adicionar o HTML antes do elemento beforeHTMLUnsafe(html, options); streamBeforeHTMLUnsafe(options);
Adicione o HTML como o primeiro filho do elemento prependHTMLUnsafe(html, options); streamPrependHTMLUnsafe(options);
Adicione o HTML como o último filho do elemento appendHTMLUnsafe(html, options); streamAppendHTMLUnsafe(options);
Adicione o HTML depois do elemento afterHTMLUnsafe(html, options); streamAfterHTMLUnsafe(options);
Os métodos de inserção e transmissão "inseguros"

Esses métodos "inseguros" desativam o higienizador por padrão (é possível especificar um higienizador personalizado, se quiser) e também permitem que scripts sejam executados com uma opção runScripts opcional (que é false por padrão).

Assim como setHTML, setHTMLUnsafe é um método existente, mas o parâmetro de opções runScripts foi adicionado para permitir o uso com a execução de script:

const newHTML = `<p>This is a new paragraph</p>
                 <script src=script.js></script>`;
const contentElement = document.querySelector('#content-to-update');

contentElement.setHTMLUnsafe(newHTML, {runScripts: true});

A palavra "inseguro" no método serve para lembrar os desenvolvedores do risco potencial e de como eles podem querer limpar ou restringir scripts, não para dizer que esses métodos não devem ser usados.

O nível de risco depende da confiabilidade das entradas. Os métodos estáticos Unsafe funcionam com DOM String ou TrustedHTML como argumentos html e também permitem o uso de sanitizadores. No entanto, com runScript, a intenção é permitir scripts. Por isso, nenhum higienizador é usado por padrão.

Casos de uso

Com essas novas APIs, os desenvolvedores podem adicionar HTML a páginas atuais com mais facilidade, além de novas APIs com nomes e opções consistentes. As APIs de streaming trazem os benefícios de performance de não precisar esperar até que todo o novo conteúdo esteja disponível para a plataforma.

Os casos de uso incluem:

  • Streaming dinâmico de grandes atualizações de conteúdo em apps de página única. Como mencionado anteriormente, uma grande desvantagem dos SPAs atuais é que eles não podem se beneficiar da natureza de streaming dos carregamentos iniciais de HTML, até agora!
  • Inserir conteúdo comum, como rodapés em HTML. Usar as APIs JavaScript permite extrair parciais e inseri-las na página, aproveitando o cache em vez de repeti-las em todas as páginas enviadas. No entanto, devido à dependência do JavaScript para execução, isso só deve ser usado para conteúdo que não vai ficar visível no carregamento inicial.

Esses são apenas alguns exemplos, e estamos ansiosos para ver o que vocês vão criar!

Restrições e sutilezas

Essas novas APIs também incluem algumas restrições e sutilezas que precisam ser consideradas:

  • A integração do streaming com a API Trusted Types exige o uso de um novo método createParserOptions, que permite injetar um higienizador em qualquer operação de configuração HTML. Consulte a explicação para mais detalhes sobre a integração de tipos confiáveis.
  • Semelhante a <template for>, mover elementos que estão sendo transmitidos pode criar consequências inesperadas ou erros de transmissão.
  • O streamHTMLUnsafe funciona mais como o analisador principal de várias maneiras, incluindo o processamento de instruções <template for> à medida que são adicionadas ao documento principal e o adiamento de scripts defer até o final do fluxo.

Polyfill

A equipe do Chrome lançou um html-setters-polyfill disponível no npm para que os sites usem essa nova funcionalidade imediatamente, mesmo antes de ela ser lançada em outros navegadores.

Observe que este polyfill não faz streaming. Em vez disso, ele armazena em buffer e aplica quando está completo. É mais um polyfill para o formato da API do que para a funcionalidade.

Além disso, a definição de conteúdo seguro depende do setHTML e da API Sanitizer, que não é compatível com o Safari.

Use os dois juntos

Embora sejam duas APIs separadas, o verdadeiro poder vem da combinação delas. Ao transmitir novos elementos <template for> para o HTML, você pode atualizar dinamicamente diferentes partes do conteúdo sem precisar segmentar cada uma diretamente com referências separadas do JavaScript ao DOM.

Um carregamento de página básico no estilo SPA pode ser implementado carregando uma página de estrutura com instruções de processamento e, em seguida, transmitindo os modelos de cada nova página para a parte inferior do HTML para se encaixar nessas instruções de processamento.

Sem dúvida, há mais potencial e casos de uso para essas duas APIs. Por isso, não deixe que nossa imaginação (limitada!) impeça você. Ao facilitar o gerenciamento de atualizações parciais, você pode reduzir parte do código boilerplate, facilitar as atualizações e desbloquear um novo potencial para a Web.