Actualizaciones parciales declarativas

Fecha de publicación: 19 de mayo de 2026

Hace mucho tiempo que la Web dejó de ser el medio estático basado en documentos que era en sus inicios. Todo el mundo usa apps web modernas y enriquecidas por muchos motivos, desde comunicarse, comprar y consumir contenido enriquecido hasta administrar nuestras vidas complejas.

A pesar de todos sus avances, el lenguaje HTML sigue entregándose en orden, de arriba hacia abajo, sin tener en cuenta cuándo el contenido está listo o cuándo el usuario lo consume. CSS te permite cambiar el orden del contenido, pero a menudo con efectos secundarios significativos en la accesibilidad. JavaScript te permite manipular el DOM a través de varias APIs para liberarte un poco de esto, pero a menudo requieren una sintaxis detallada o la construcción de árboles del DOM para conectarse a HTML.

El rendimiento es increíblemente importante para la Web, dada la naturaleza cliente-servidor del medio, pero a menudo se toman decisiones subóptimas para evitar esta naturaleza ordenada del HTML, lo que ralentiza el rendimiento. Esto incluye esperar hasta que toda la página esté lista o usar un framework pesado para entregar componentes de forma asíncrona. La popularidad de los frameworks de JavaScript demuestra que los desarrolladores web prefieren un modelo basado en componentes en lugar del modelo mental rígido de documentos de los orígenes de la Web.

El equipo de Chrome ha estado considerando este problema y ha desarrollado nuevas incorporaciones a la plataforma web con el nombre de Actualizaciones parciales declarativas.

Dos nuevos conjuntos de APIs facilitan la entrega de HTML de una manera menos lineal, ya sea fuera de orden en el documento HTML o a través de formas más sencillas de insertar HTML de forma dinámica en documentos existentes con nuevas APIs de JavaScript. Estas funciones están listas para que los desarrolladores las prueben a partir de Chrome 148 con la marca chrome://flags/#enable-experimental-web-platform-features. También hay polyfills disponibles para que puedas usar estas nuevas APIs de inmediato, incluso en navegadores que aún no las admiten.

Estas incorporaciones a la plataforma web se están estandarizando con comentarios positivos de otros proveedores de navegadores y vías de estandarización. Los estándares pertinentes se están actualizando para incluir estas nuevas APIs.

Transmisión desordenada

El primer conjunto de cambios son las nuevas APIs de transmisión fuera de orden que usan el elemento HTML <template> y marcadores de posición de instrucciones de procesamiento. Por ejemplo:

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

...

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

Las instrucciones de procesamiento existen en XML desde hace mucho tiempo, pero se trataron como comentarios en HTML y se ignoraron. Esta nueva API cambia eso y agrega instrucciones de procesamiento a HTML. Cuando el navegador ve las instrucciones de procesamiento de <?marker name="placeholder">, no hace nada de inmediato, al igual que antes, pero se puede hacer referencia a ellas más adelante.

El elemento <template> busca las instrucciones de procesamiento correspondientes con un atributo name y reemplaza el contenido. En este caso, después de analizarse, el DOM termina de la siguiente manera:

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

Además del atributo <?marker> para los reemplazos, también hay marcadores de rango <?start> y <?end> que permiten mostrar contenido de marcador de posición temporal antes de que se procese la plantilla:

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

...

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

En este caso, Loading… se muestra hasta que se ve <template> y, luego, se reemplaza por el contenido nuevo.

También es posible incluir instrucciones de procesamiento en las plantillas para permitir varias actualizaciones:

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

Esto genera el siguiente código HTML después del análisis:

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

Con la instrucción de procesamiento final al final, en caso de que se agreguen más <template for="results"> al documento más adelante.

Demostración

En este video, se implementa una aplicación básica de álbum de fotos con HTML de transmisión continua:

Demostración de álbum de fotos implementada con transmisión fuera de orden (fuente)

Tanto el estado como las fotos se transmiten al HTML después del diseño inicial.

Casos de uso

Existen muchos casos de uso para esta aplicación de parches HTML fuera de orden cuando se combina con la transmisión de HTML:

  • Arquitectura de islas Un patrón común popularizado por frameworks como Astro es la arquitectura de islas, en la que los componentes se hidratan de forma independiente sobre HTML estático. La API de <template for> permite que el contenido estático se controle de manera similar directamente en HTML. Los frameworks de JavaScript también pueden usarlo para islas más interactivas o para controlar componentes.
  • Publica el contenido cuando esté listo. Gracias a esta arquitectura de islas, el contenido se puede transmitir cuando está listo en lugar de retenerse para el contenido que requiere un procesamiento adicional, por ejemplo, una búsqueda en la base de datos. Si bien muchas plataformas permiten la transmisión de HTML, la naturaleza ordenada de este lenguaje implica que, a menudo, el contenido se retrasa o se recurre a manipulaciones complejas del DOM de JavaScript. Ahora puedes entregar el contenido estático mientras esperas y, luego, insertar el contenido más costoso al final del flujo de HTML.
  • El código HTML se puede entregar en el orden óptimo para el rendimiento de carga de la página. Si vas un paso más allá, puedes cambiar el orden incluso cuando esté listo. Por ejemplo, los menús desplegables son una función de navegación común que contiene mucho código HTML que el usuario no verá hasta que la página se vuelva interactiva. Este gran fragmento de HTML se puede entregar más adelante en el documento HTML para priorizar el HTML más importante que se necesita para la carga inicial de la página. El orden ya no es una barrera con HTML.

Estos son solo algunos casos de uso, y es emocionante ver para qué usarán los desarrolladores esta nueva API.

Restricciones y detalles

La API incluye algunas restricciones y detalles que debes tener en cuenta:

  • Por motivos de seguridad, <template for> solo puede actualizar las instrucciones de procesamiento dentro del mismo elemento principal. Si agregas <template for> directamente al elemento <body>, este tendrá acceso a todo el documento (incluido el <head>).
  • La instrucción de procesamiento <?end> es opcional y, si falta, se reemplazará el contenido entre el elemento <?start> y el final del elemento contenedor.
  • Mover las instrucciones de procesamiento después de que se haya comenzado a transmitir un <template for> también puede tener consecuencias inesperadas, ya que el contenido nuevo seguirá transmitiéndose a la ubicación anterior.
  • Ten en cuenta que, cuando se inserta <template for> de forma dinámica con métodos como setHTML o innerHTML, el "elemento superior" de la plantilla cuando se analiza es un fragmento de documento intermedio. Esto significa que la inserción de HTML con estos métodos no puede modificar el DOM existente, y la aplicación de parches se realiza "in situ" dentro del fragmento. Sin embargo, cuando se transmite contenido con métodos como streamHTMLUnsafe (que explicaremos en breve), no hay fragmentos intermedios, por lo que las plantillas pueden reemplazar el contenido existente.

Posibles incorporaciones futuras

Entre las posibles incorporaciones futuras que se están considerando, se incluyen las siguientes:

  • Incluye el lado del cliente. Por ejemplo, <template for="footer" patchsrc="/partials/footer.html">
  • Agrupación en lotes: En el cliente, las inclusiones de fragmentos también se podrían extender para controlar el procesamiento por lotes y garantizar que se realicen varias actualizaciones al mismo tiempo.
  • Evita sobrescribir el contenido que no cambiará. Esto se podría lograr con un número de revisión o control de versiones del contenido. Esto permitiría mantener el estado entre los cambios de ruta o las actualizaciones, en lugar de restablecer el contenido.
  • Desinfección durante la aplicación de parches: Por ejemplo, <template for=icon safe><svg id="from-untrusted-source">...</svg></template>

Polyfill

El equipo de Chrome lanzó un template-for-polyfill que está disponible en npm para permitir que los sitios usen esta nueva funcionalidad de inmediato, incluso antes de que se lance en otros navegadores.

Existen algunas limitaciones, ya que no puede actualizar directamente los analizadores de HTML del navegador, pero se cubren los casos de uso más comunes. Los sitios deben seguir probándose en otros navegadores.

Se renovaron los métodos de inserción y transmisión de HTML

No todo el contenido se puede entregar en HTML. Una segunda parte del trabajo que Chrome está realizando en esta área implica facilitar la actualización del contenido a través de JavaScript.

Ya existen varias formas de insertar HTML de forma dinámica en un documento existente con JavaScript:

  • setHTML
  • setHTMLUnsafe
  • Métodos de configuración de innerHTML y outerHTML
  • createContextualFragment
  • insertAdjacentHTML

Sin embargo, todos funcionan de maneras ligeramente diferentes, con sutilezas y diferencias que los desarrolladores no siempre tienen en cuenta:

  • ¿El contenido nuevo reemplaza o se agrega?
  • ¿Sanean el código HTML potencialmente peligroso escapando las etiquetas <script>, por ejemplo?
  • Si no es así, ¿se debería ejecutar <script>?
  • ¿Cómo funcionan con Trusted Types?

Pocos desarrolladores podrían mirar esas APIs con honestidad y responder con confianza esas preguntas para cada una de ellas.

Una gran limitación es que solo se pueden usar para un conjunto completo de HTML conocido de antemano, cuando se realizaron llamadas para permitir el streaming de HTML. En la práctica, esto significa que debes descargar todo el contenido antes de insertarlo, cuando uno de los puntos fuertes del HTML es la capacidad de transmitir contenido de inmediato. Esto se puede solucionar de forma limitada dividiendo las cargas útiles o usando métodos hacky y obsoletos como document.write, pero estos introducen sus propios problemas.

Un nuevo conjunto de APIs de transmisión y estáticas

Chrome propuso un conjunto de nuevas APIs y extensiones para las existentes setHTML y setHTMLUnsafe que solucionan este problema, además de introducir la funcionalidad de transmisión:

Existen métodos para establecer o reemplazar, junto con métodos para insertar contenido antes o después del código HTML existente. Cada método tiene equivalentes de transmisión:

Acción Estática Transmisión
Establece el contenido HTML del elemento setHTML(html, options); streamHTML(options);
Reemplaza todo el elemento con este código HTML replaceWithHTML(html, options); streamReplaceWithHTML(options);
Agrega el código HTML antes del elemento beforeHTML(html, options); streamBeforeHTML(options);
Agrega el código HTML como el primer elemento secundario del elemento. prependHTML(html, options); streamPrependHTML(options);
Agrega el código HTML como el último elemento secundario del elemento. appendHTML(html, options); streamAppendHTML(options);
Agrega el código HTML después del elemento afterHTML(html, options); streamAfterHTML(options);
Los nuevos métodos de inserción y transmisión

También hay versiones Unsafe, de las que hablaremos en breve. Si bien puede parecer que hay muchos (en especial cuando agregas los equivalentes de Unsafe), la convención de nomenclatura coherente hace que sea más obvio lo que hace cada uno en comparación con los métodos no relacionados que se mencionaron anteriormente.

Las versiones estáticas toman el nuevo HTML como un argumento de cadena DOM, junto con opciones opcionales:

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

contentElement.setHTML(newHTML);

Las versiones de transmisión funcionan con la API de Streams, como con un 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();

O, como alternativa, desde una respuesta de recuperación, con cadenas de canalización:

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

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

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

También planeamos agregar un método conveniente en el que puedas transmitir directamente sin necesidad del paso intermedio TextDecoderStream().

El argumento options te permite especificar un sanitizer personalizado que, de forma predeterminada, se establece en default, lo que significa la configuración predeterminada del sanitizador. Se usa de la siguiente manera:

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"

También hay versiones "inseguras" de cada una de las APIs:

Acción Estática Transmisión
Establece el contenido HTML del elemento setHTMLUnsafe(html,options); streamHTMLUnsafe(options);
Reemplaza todo el elemento con este código HTML replaceWithHTMLUnsafe(html, options); streamReplaceWithHTMLUnsafe(options);
Agrega el código HTML antes del elemento beforeHTMLUnsafe(html, options); streamBeforeHTMLUnsafe(options);
Agrega el código HTML como el primer elemento secundario del elemento. prependHTMLUnsafe(html, options); streamPrependHTMLUnsafe(options);
Agrega el código HTML como el último elemento secundario del elemento. appendHTMLUnsafe(html, options); streamAppendHTMLUnsafe(options);
Agrega el código HTML después del elemento afterHTMLUnsafe(html, options); streamAfterHTMLUnsafe(options);
Los métodos de inserción y transmisión “inseguros”

Estos métodos "inseguros" desactivan el filtro de forma predeterminada (puedes especificar un filtro personalizado si lo deseas) y también permiten que se ejecuten secuencias de comandos con una opción runScripts opcional (que se establece de forma predeterminada en false).

Al igual que setHTML, setHTMLUnsafe es un método existente, pero se le agregó el parámetro de opciones runScripts para permitir que se use con la ejecución de secuencias de comandos:

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});

La palabra "inseguro" en el método tiene como objetivo recordarles a los desarrolladores el riesgo potencial y cómo podrían querer limpiar o restringir los scripts, no decir que estos métodos no se deben usar.

El nivel de "inseguridad" depende de la confiabilidad de las entradas. Todos los métodos estáticos de Unsafe funcionan con cadenas DOM o TrustedHTML como argumentos de html y también permiten el uso de saneadores. Sin embargo, con runScript, la intención es permitir scripts, por lo que, de forma predeterminada, no se usa ningún sanitizador.

Casos de uso

Estas nuevas APIs facilitan a los desarrolladores la tarea de agregar HTML a las páginas existentes, ya que incorporan APIs nuevas con nombres y opciones coherentes. Las APIs de transmisión brindan los beneficios de rendimiento de no tener que esperar hasta que todo el contenido nuevo esté disponible en la plataforma.

En los casos de uso, se incluye lo siguiente:

  • Transmisión dinámica de actualizaciones de contenido grandes en aplicaciones de una sola página. Como se mencionó anteriormente, una gran desventaja de las SPA actuales es que no se pueden beneficiar de la naturaleza de transmisión de las cargas iniciales de HTML, hasta ahora.
  • Insertar contenido común, como pies de página en HTML El uso de las APIs de JavaScript te permite extraer parciales e insertarlos en la página, lo que se beneficia del almacenamiento en caché, en lugar de repetirlos en cada página enviada. Sin embargo, dada la dependencia de JavaScript para ejecutarse, esto solo debe usarse para el contenido que no se verá en la carga inicial.

Una vez más, estos son solo algunos ejemplos, y nos entusiasma ver lo que se les ocurre a todos.

Restricciones y detalles

Estas nuevas APIs también incluyen algunas restricciones y detalles que debes tener en cuenta:

  • La integración de la transmisión con la API de Trusted Types requiere el uso de un nuevo método createParserOptions que permite insertar un sanitizador en cualquier operación de configuración de HTML. Consulta la explicación para obtener más detalles sobre la integración de Trusted Types
  • Al igual que <template for>, mover elementos que se transmiten puede generar consecuencias inesperadas o errores de transmisión.
  • streamHTMLUnsafe funciona más como el analizador principal en muchos sentidos, incluido el procesamiento de las instrucciones <template for> a medida que se agregan al documento principal y el aplazamiento de las secuencias de comandos defer hasta el final de la transmisión.

Polyfill

El equipo de Chrome lanzó un html-setters-polyfill que está disponible en npm para permitir que los sitios usen esta nueva funcionalidad de inmediato, incluso antes de que se lance en otros navegadores.

Ten en cuenta que este polyfill no transmite, sino que se almacena en búfer y se aplica cuando se completa. Es más un polyfill para la forma de la API que para la funcionalidad.

Además, la configuración de contenido seguro depende de setHTML y de la API de Sanitizer, que no es compatible con Safari.

Usar ambas en conjunto

Si bien estas son dos APIs independientes, el verdadero poder reside en combinarlas. Si transmites nuevos elementos <template for> al HTML, puedes actualizar de forma dinámica diferentes partes del contenido sin tener que segmentar directamente cada una con referencias de JavaScript independientes al DOM.

Se podría implementar una carga de página básica al estilo de SPA cargando una página de esquema con instrucciones de procesamiento y, luego, transmitiendo las plantillas de cada página nueva a la parte inferior del HTML para insertarlas en esas instrucciones de procesamiento.

Sin duda, hay más potencial y casos de uso para ambas APIs, así que no dejes que nuestra imaginación (limitada) te detenga. Al facilitar la administración de las actualizaciones parciales, puedes reducir parte del código estándar, facilitar las actualizaciones y desbloquear nuevas posibilidades para la Web.