Atualizações parciais declarativas

Publicado em: 19 de maio de 2026, última atualização: 8 de setembro de 2026

A Web já se distanciou bastante do 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 e consumo de conteúdo avançado até o gerenciamento de nossas vidas complexas.

O HTML, apesar de todos os avanços, ainda é entregue em ordem, de cima para baixo, sem considerar 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 de acessibilidade. O JavaScript permite manipular o DOM usando várias APIs para se livrar um pouco disso, mas elas geralmente exigem uma sintaxe detalhada ou a construção de árvores do DOM para serem conectadas ao HTML.

A performance é extremamente importante para a Web, devido à natureza cliente-servidor do meio. No entanto, muitas vezes são feitas escolhas abaixo do ideal para contornar essa natureza ordenada do HTML, o que reduz o desempenho. Isso inclui esperar até que toda a página esteja pronta ou usar um framework pesado para entregar componentes de maneira assíncrona. A popularidade dos frameworks de JavaScript mostra que os desenvolvedores web preferem um modelo baseado em componentes em vez do modelo mental de documento rígido das origens da Web.

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

Os dois primeiros 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. Os polyfills também estão disponíveis para que você possa usar essas novas APIs imediatamente, mesmo em navegadores que ainda não são compatíveis com elas.

Streaming fora de ordem

Browser Support

  • Chrome: 150.
  • Edge: 150.
  • Firefox: not supported.
  • Safari: not supported.

Source

O primeiro conjunto de mudanças são as novas APIs de streaming fora de ordem que usam marcadores de posição de instrução de processamento e o elemento HTML <template> com o atributo for. 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 o HTML. Por exemplo, quando o navegador vê a instrução de processamento <?marker name="placeholder">, ele não faz nada imediatamente, como antes, mas pode ser referenciado mais tarde.

O elemento <template> com o atributo for procura as instruções de processamento correspondentes com um atributo name e substitui o conteúdo. Nesse caso, após ser analisado, o DOM fica assim (ignorando algumas diferenças de espaço em branco):

<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 que o conteúdo temporário do marcador de posição seja mostrado antes do processamento do modelo:

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

...

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

Nesse caso, uma string Loading… é mostrada até que o <template> seja visto e, em seguida, é substituída 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 ser analisado e processado:

<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 marcadores de posição <template for="results"> sejam adicionados ao documento posteriormente.

Por que usar instruções de processamento em vez de elementos HTML padrão?

Essa é uma pergunta comum para quem está usando essa API pela primeira vez, com sugestões para usar elementos <slot> ou até mesmo <template>. Uma versão inicial dessa proposta funcionava com elementos HTML padrão, mas as instruções de processamento foram alteradas conforme o design foi iterado. As instruções de processamento permitem que a aplicação de patches aconteça sem afetar o DOM. Isso permite que ele seja usado no <head>, por exemplo, para atualizações de <title>, ou até mesmo dentro de outros elementos, como <table> (para adicionar linhas extras opcionais, por exemplo).

Embora a sintaxe não seja familiar para muitos desenvolvedores web, as instruções de processamento oferecem muito mais flexibilidade com menos chance de problemas de compatibilidade com versões anteriores. Eles já são usados em XML e, graças a essa proposta, agora fazem parte do padrão HTML.

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 HTML de patch fora de ordem quando combinado com o HTML de streaming:

  • 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 sobre o HTML estático. A API <template for> permite que o conteúdo estático seja processado de maneira semelhante diretamente em HTML. Os frameworks de JavaScript também podem usar isso para ilhas mais interativas ou para processar componentes.
  • Entregar o conteúdo quando 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, como uma pesquisa de banco de dados. Embora muitas plataformas permitam o streaming de HTML, a natureza ordenada do HTML significa que o conteúdo geralmente é retido ou que é preciso recorrer a manipulações complexas do DOM do JavaScript. Agora, você pode entregar o conteúdo estático enquanto espera e, em seguida, conectar conteúdo mais caro e dinâmico no final do stream HTML.
  • O HTML pode ser entregue na ordem ideal para o desempenho do carregamento de página. Além disso, é possível mudar o pedido mesmo quando ele estiver pronto. Por exemplo, os megamenus são um recurso de navegação comum que contém muito HTML que o usuário não vai ver até que a página se torne interativa. Esse grande bloco de 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 o HTML.

Esses são apenas alguns casos de uso, e estamos ansiosos para ver como os desenvolvedores vão usar essa nova API.

Restrições e sutilezas

A API inclui algumas restrições e detalhes que você precisa conhecer:

  • <template for> só pode atualizar instruções de processamento no mesmo elemento pai por motivos de segurança. 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 final do elemento que o contém será substituído.
  • Mover as instruções de processamento depois que um <template for> começar 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 a propriedade innerHTML, o "pai" do modelo quando ele é analisado é um fragmento de documento intermediário. Isso significa que a inserção de HTML com esses métodos não pode modificar o DOM atual, e a correção acontece "no local" dentro do fragmento. No entanto, ao fazer streaming usando métodos como streamHTMLUnsafe (abordado em breve), não há fragmento intermediário, então os modelos podem substituir o conteúdo atual.

Status da padronização

O atributo <template for> faz parte do padrão HTML, mas ainda não é compatível com todos os navegadores.

Possíveis adições futuras

Algumas possíveis adições futuras que estão sendo consideradas incluem:

  • Inclusões do lado do cliente. Por exemplo, <template for="footer" src="/partials/footer.html"> ou mesmo sem aplicar patch em <template src="/partials/footer.html">. Para mais detalhes, consulte o explicativo. Isso está disponível na flag chrome://flags/#enable-experimental-web-platform-features.
  • 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 permitiria que o estado fosse mantido entre mudanças de rota ou outras atualizações, em vez de redefinir o conteúdo.
  • Limpeza durante a aplicação de patches. Por exemplo, <template for=icon safe><svg id="from-untrusted-source">...</svg></template>

Polyfill

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

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

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

Nem todo conteúdo pode ser entregue como HTML. A segunda parte do trabalho do Chrome nessa área visa facilitar a atualização de conteúdo com JavaScript.

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

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

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

  • O novo conteúdo substitui ou é adicionado ao final?
  • Eles limpam HTML potencialmente perigoso, por exemplo, escapando tags <script>?
  • Caso contrário, o <script> deve ser executado?
  • Como eles funcionam com os Tipos confiáveis?

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

Uma grande limitação é que eles só podem ser usados para um conjunto completo de HTML conhecido com antecedência, quando há chamadas para permitir que o HTML seja transmitido. Na prática, isso significa que você precisa baixar todo o conteúdo antes de inseri-lo, quando um dos pontos fortes do HTML é a capacidade de fazer streaming de conteúdo imediatamente. Isso pode ser contornado de forma limitada dividindo os payloads ou usando métodos obsoletos e de baixa qualidade, como document.write, mas eles introduzem os próprios problemas.

Um novo conjunto de APIs estáticas e de streaming

Browser Support

  • Chrome: behind a flag.
  • Edge: behind a flag.
  • Firefox: not supported.
  • Safari: not supported.

O Chrome trabalhou em um conjunto de novas APIs e extensões para as setHTML e setHTMLUnsafe atuais que limpam isso, além de introduzir a funcionalidade de streaming.

Eles estão prontos para testes de desenvolvedores no Chrome 148 usando a flag chrome://flags/#enable-experimental-web-platform-features e estão planejados para lançamento no Chrome 155.

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);
Adicionar o HTML como o primeiro filho do elemento prependHTML(html, options); streamPrependHTML(options);
Adicionar o HTML como o último filho do elemento appendHTML(html, options); streamAppendHTML(options);
Adicionar o HTML após o elemento afterHTML(html, options); streamAfterHTML(options);
Os novos métodos de inserção e streaming

Também há versões do Unsafe que serão abordadas em breve. Embora pareça haver muitos deles, especialmente quando você adiciona os equivalentes de 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 o novo HTML como um argumento de string do 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, como alternativa, de uma resposta de busca usando cadeias de pipe:

const contentElement = document.querySelector('#content-to-update');
const response = await fetch('/api/content.html');

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

Método de conveniência textStream()

Browser Support

  • Chrome: 151.
  • Edge: 151.
  • Firefox: not supported.
  • Safari: not supported.

Source

Também foi adicionado um método de conveniência textStream, em que é possível fazer streaming diretamente sem precisar da etapa intermediária TextDecoderStream():

const contentElement = document.querySelector('#content-to-update');
const response = await fetch('/api/content.html');

response.textStream().pipeTo(contentElement.streamHTMLUnsafe());

options

O argumento options permite especificar um sanitizer personalizado, que tem como padrão default, o que significa a configuração padrão do limpador. 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 "não seguros"

Também há versões "não seguras" 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);
Adicionar o HTML como o primeiro filho do elemento prependHTMLUnsafe(html, options); streamPrependHTMLUnsafe(options);
Adicionar o HTML como o último filho do elemento appendHTMLUnsafe(html, options); streamAppendHTMLUnsafe(options);
Adicionar o HTML após o elemento afterHTMLUnsafe(html, options); streamAfterHTMLUnsafe(options);
Os métodos de inserção e streaming "não seguros"

Esses métodos "não seguros" desativam o limpador por padrão, e você pode especificar um limpador personalizado, se quiser. Esses métodos também permitem que os scripts sejam executados com uma opção runScripts opcional, que tem como padrão false.

Assim como setHTML, setHTMLUnsafe é um método que já existe, 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 "unsafe" (não seguro) no método serve para lembrar os desenvolvedores do risco potencial e de como eles podem limpar ou restringir scripts, não para dizer que esses métodos não devem ser usados.

O nível de "insegurança" depende da confiabilidade das entradas. Todos os métodos estáticos Unsafe funcionam com strings DOM ou TrustedHTML como argumentos html e também permitem o uso de limpadores. No entanto, com runScript, a intenção é permitir scripts, por isso nenhum limpador é usado por padrão.

Casos de uso

Essas novas APIs facilitam a adição de HTML a páginas existentes, adicionando novas APIs com nomes e opções consistentes. As APIs de streaming trazem os benefícios de desempenho de não ter que 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 do arquiteto de SPA atual é que ele não se beneficia da natureza de streaming dos carregamentos iniciais de HTML, até agora.
  • Inserir conteúdo comum, como rodapés HTML. O uso das APIs JavaScript permite extrair parciais e inseri-las na página, aproveitando o armazenamento em cache, em vez de repeti-las em todas as páginas enviadas. No entanto, como depende do JavaScript para ser executado, ele 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 detalhes que você precisa conhecer:

  • A integração do streaming com a API Trusted Types exige o uso de um novo método createParserOptions, que permite injetar um limpador em qualquer operação de configuração de HTML. Consulte o documento explicativo para mais detalhes sobre a integração de tipos confiáveis.
  • Assim como em <template for>, mover elementos que estão sendo transmitidos pode criar consequências inesperadas ou erros de transmissã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 stream.

Status da padronização

Os métodos mais recentes de inserção e streaming estão em processo de adição ao padrão HTML, mas ainda não são compatíveis com todos os navegadores.

Polyfill

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

Esse polyfill não faz streaming, mas armazena em buffer e aplica quando concluído. É mais um polyfill para o formato da API do que para a funcionalidade.

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

Use os dois juntos

Embora sejam duas APIs separadas, o verdadeiro potencial delas aparece quando são combinadas. Ao transmitir novos elementos <template for> para o HTML, é possível atualizar dinamicamente diferentes partes do conteúdo sem precisar segmentar cada uma delas com referências JavaScript separadas para o 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 de baixo do HTML para se encaixar nessas instruções de processamento.

Sem dúvida, há mais potencial e casos de uso para essas duas APIs. Portanto, não deixe que nossa imaginação (limitada!) limite 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.

Há mais algumas APIs em que o Chrome está trabalhando no projeto de atualizações parciais declarativas, mas estamos felizes em disponibilizar as duas primeiras. Vamos manter você por dentro das novidades e avisar quando mais recursos estiverem disponíveis.