Declaratieve gedeeltelijke updates

Gepubliceerd: 19 mei 2026, Laatst bijgewerkt: 8 september 2026

Het web is allang niet meer het statische, documentgedreven medium waarmee het begon. Moderne, geavanceerde webapplicaties worden door iedereen gebruikt voor allerlei doeleinden, van communicatie en online winkelen tot het consumeren van rijke content en het beheren van ons complexe leven.

Ondanks alle vooruitgang wordt HTML nog steeds van boven naar beneden geladen, zonder veel rekening te houden met wanneer de inhoud gereed is of wanneer de gebruiker deze consumeert. Met CSS kun je de volgorde van de inhoud wijzigen, maar dit gaat vaak ten koste van de toegankelijkheid. JavaScript stelt je in staat om de DOM te manipuleren via verschillende API's om dit enigszins te omzeilen, maar dit vereist vaak een omslachtige syntaxis of de constructie van DOM-structuren om in HTML te integreren.

Prestaties zijn ongelooflijk belangrijk voor het web, gezien het client-serverkarakter van het medium. Er worden echter vaak suboptimale keuzes gemaakt om deze volgorde van HTML te omzeilen, wat de prestaties vertraagt. Dit omvat bijvoorbeeld wachten tot de hele pagina gereed is of het gebruik van een zwaar framework om componenten asynchroon te leveren. De populariteit van JavaScript-frameworks laat zien dat webontwikkelaars de voorkeur geven aan een componentgebaseerd model boven het rigide documentmodel dat aan de basis stond van het web.

Het Chrome-team heeft zich over dit probleem gebogen en werkt aan nieuwe toevoegingen aan het webplatform onder de naam Declarative Partial Updates .

De eerste twee nieuwe API-sets maken het eenvoudiger om HTML op een minder lineaire manier te leveren, ofwel door HTML in een andere volgorde in het HTML-document zelf te plaatsen, ofwel door op eenvoudigere manieren dynamisch HTML in bestaande documenten in te voegen met behulp van nieuwe JavaScript-API's. Er zijn ook polyfills beschikbaar waarmee u deze nieuwe API's direct kunt gebruiken, zelfs in browsers die ze nog niet ondersteunen.

Streaming in een verkeerde volgorde

Browser Support

  • Chroom: 150.
  • Rand: 150.
  • Firefox: niet ondersteund.
  • Safari: niet ondersteund.

Source

De eerste reeks wijzigingen betreft nieuwe API's voor streaming in een andere volgorde, waarbij gebruik wordt gemaakt van placeholders voor verwerkingsinstructies en het HTML-element <template> met het attribuut for . Bijvoorbeeld:

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

...

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

Verwerkingsinstructies bestaan ​​al lange tijd in XML, maar werden in HTML als commentaar behandeld en genegeerd. Deze nieuwe API verandert dat en brengt verwerkingsinstructies naar HTML. Wanneer de browser bijvoorbeeld de verwerkingsinstructie <?marker name="placeholder"> ziet, gebeurt er niet direct iets – net als voorheen – maar er kan later naar worden verwezen.

Het <template> -element met het for attribuut zoekt de overeenkomstige verwerkingsinstructies op met een name attribuut en vervangt de inhoud. In dit geval ziet de DOM er na het parsen als volgt uit (waarbij we enkele verschillen in witruimte negeren):

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

Naast het <?marker> -attribuut voor vervangingen zijn er ook <?start> en <?end> -bereikmarkeringen waarmee tijdelijke placeholder-inhoud kan worden weergegeven voordat de sjabloon wordt verwerkt:

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

...

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

In dit geval wordt de tekst Loading… " weergegeven totdat de <template> zichtbaar is, waarna deze wordt vervangen door de nieuwe inhoud.

Het is ook mogelijk om verwerkingsinstructies in sjablonen op te nemen, zodat meerdere updates mogelijk zijn:

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

...

Na het parsen en verwerken resulteert dit in de volgende HTML-code:

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

Met de laatste verwerkingsinstructie aan het einde, voor het geval er later nog <template for="results"> placeholders aan het document worden toegevoegd.

Waarom verwerkingsinstructies in plaats van standaard HTML-elementen?

Dit is een veelgestelde vraag voor degenen die deze API voor het eerst gebruiken, waarbij vaak wordt gesuggereerd om <slot> of zelfs <template> elementen te gebruiken. Een eerste versie van dit voorstel werkte met standaard HTML-elementen, maar tijdens de verdere ontwikkeling van het ontwerp werd overgeschakeld naar verwerkingsinstructies. Verwerkingsinstructies maken het mogelijk om wijzigingen aan te brengen zonder de DOM te beïnvloeden. Hierdoor kan dit bijvoorbeeld in de <head> worden gebruikt — voor <title> updates — of zelfs binnen andere elementen zoals <table> (om bijvoorbeeld optionele extra rijen toe te voegen).

Hoewel de syntaxis voor veel webontwikkelaars onbekend is, bieden verwerkingsinstructies veel meer flexibiliteit met minder kans op problemen met achterwaartse compatibiliteit. Ze worden al gebruikt in XML en maken dankzij dit voorstel nu deel uit van de HTML-standaard .

Demo

In deze video wordt een eenvoudige fotoalbumapplicatie geïmplementeerd met behulp van streaming HTML:

Demo van een fotoalbum met streaming in willekeurige volgorde ( bron )

Zowel de status als de foto's worden na de initiële lay-out in de HTML-code geladen.

Gebruiksvoorbeelden

Er zijn veel toepassingsmogelijkheden voor deze methode om HTML in een andere volgorde te patchen, in combinatie met streaming HTML:

  • Eilandarchitectuur. Een veelvoorkomend patroon, populair gemaakt door frameworks zoals Astro, is de eilandarchitectuur waarbij componenten onafhankelijk van elkaar worden geladen bovenop statische HTML. De <template for> -API maakt het mogelijk om statische content op een vergelijkbare manier direct in HTML te verwerken. JavaScript-frameworks kunnen dit ook gebruiken voor meer interactieve eilanden of om componenten te beheren.
  • Lever content aan zodra deze gereed is. Dankzij deze eilandarchitectuur kan content worden gestreamd zodra deze gereed is, in plaats van te worden tegengehouden voor content die extra verwerking vereist, zoals bijvoorbeeld een databasequery. Hoewel veel platforms het streamen van HTML toestaan, zorgt de in-order aard van HTML ervoor dat content vaak wordt tegengehouden of dat er gebruik wordt gemaakt van complexe JavaScript DOM-manipulaties. Nu kunt u de statische content leveren terwijl u wacht, en vervolgens de duurdere en dynamische content aan het einde van de HTML-stream toevoegen.
  • HTML kan in de optimale volgorde worden geladen voor een snelle laadtijd van de pagina. Sterker nog, je kunt de volgorde zelfs nog aanpassen nadat de pagina al geladen is. Megamenu's zijn bijvoorbeeld een veelvoorkomende navigatiefunctie die veel HTML bevat die de gebruiker pas ziet wanneer de pagina interactief wordt. Dit grote stuk HTML kan later in het HTML-document worden geladen om prioriteit te geven aan belangrijkere HTML die nodig is voor de initiële paginalading. De volgorde is met HTML geen belemmering meer.

Dit zijn slechts enkele voorbeelden, en we zijn benieuwd waarvoor ontwikkelaars deze nieuwe API zullen gebruiken.

Beperkingen en nuances

De API kent een aantal beperkingen en nuances waar je rekening mee moet houden:

  • Om veiligheidsredenen kan <template for> alleen verwerkingsinstructies bijwerken binnen hetzelfde bovenliggende element. Door een <template for> rechtstreeks aan het <body> -element toe te voegen, krijgt het toegang tot het hele document (inclusief de <head> ).
  • De verwerkingsinstructie <?end> is optioneel en als deze ontbreekt, wordt de inhoud tussen het <?start> -element en het einde van het omringende element vervangen.
  • Het verplaatsen van verwerkingsinstructies nadat een <template for> is begonnen met streamen, kan ook onverwachte gevolgen hebben, waarbij de nieuwe inhoud blijft streamen naar de oude locatie.
  • Houd er rekening mee dat wanneer je dynamisch <template for> invoegt met een methode zoals setHTML of de innerHTML eigenschap, de "ouder" van het sjabloon tijdens het parsen een tussenliggend documentfragment is. Dit betekent dat het invoegen van HTML met deze methoden de bestaande DOM niet kan wijzigen en dat de aanpassing "ter plaatse" in het fragment plaatsvindt. Bij het streamen met methoden zoals streamHTMLUnsafe (waarover later meer) is er echter geen tussenliggend fragment, waardoor de sjablonen bestaande inhoud kunnen vervangen.

Standaardisatiestatus

Het attribuut <template for> maakt deel uit van de HTML-standaard , maar wordt nog niet door alle browsers ondersteund.

Toekomstige potentiële toevoegingen

Enkele mogelijke toekomstige toevoegingen die momenteel worden overwogen, zijn:

  • Client-side includes. Bijvoorbeeld <template for="footer" src="/partials/footer.html"> , of zelfs zonder patch <template src="/partials/footer.html"> . Zie de uitleg voor meer informatie. Deze functionaliteit is beschikbaar via de vlag chrome://flags/#enable-experimental-web-platform-features .
  • Voorkomen dat inhoud die niet verandert, wordt overschreven. Dit kan worden bereikt met een revisienummer of versiebeheer. Hierdoor blijft de status behouden tussen routewijzigingen of andere updates, in plaats van dat de inhoud opnieuw wordt ingesteld.
  • Opschonen tijdens het patchen. Bijvoorbeeld: <template for=icon safe><svg id="from-untrusted-source">...</svg></template>

Polyfill

Het Chrome-team heeft een template-for-polyfill uitgebracht die beschikbaar is op npm , zodat websites deze nieuwe functionaliteit direct kunnen gebruiken, zelfs voordat deze in andere browsers beschikbaar komt.

Er zijn enkele beperkingen, aangezien het de HTML-parsers van browsers niet direct kan bijwerken, maar de meest voorkomende gebruiksscenario's worden wel gedekt. ​​Websites moeten de functionaliteit nog steeds in andere browsers testen.

Vernieuwde HTML-invoeg- en streamingmethoden

Niet alle content kan als HTML worden weergegeven. Een tweede onderdeel van het werk dat Chrome op dit gebied heeft verricht, is erop gericht het eenvoudiger te maken om content met JavaScript bij te werken.

Er bestaan ​​al diverse manieren om dynamisch HTML in een bestaand document in te voegen met behulp van JavaScript:

  • setHTML
  • setHTMLUnsafe
  • innerHTML en outerHTML
  • createContextualFragment
  • insertAdjacentHTML

Ze werken echter allemaal op een iets andere manier, met subtiliteiten en verschillen waar ontwikkelaars mogelijk niet altijd aan denken:

  • Wordt de nieuwe inhoud overschreven of toegevoegd?
  • Worden potentieel gevaarlijke HTML-code gesaneerd, bijvoorbeeld door <script> -tags te escapen?
  • Zo niet, moet <script> dan worden uitgevoerd?
  • Hoe werken ze samen met vertrouwde typen ?

Weinig ontwikkelaars zouden die API's eerlijk kunnen bekijken en met vertrouwen de vragen voor elk ervan kunnen beantwoorden.

Een grote beperking is dat ze alleen gebruikt kunnen worden voor een complete set HTML die van tevoren bekend is, wanneer er aanroepen zijn gedaan om het streamen van HTML toe te staan. In de praktijk betekent dit dat je de volledige inhoud moet downloaden voordat je deze kunt invoegen, terwijl een van de sterke punten van HTML juist de mogelijkheid is om inhoud direct te streamen. Dit kan in beperkte mate worden omzeild door payloads op te splitsen of door gebruik te maken van onorthodoxe, verouderde methoden zoals document.write , maar die brengen hun eigen problemen met zich mee.

Een nieuwe set statische en streaming API's

Browser Support

  • Chrome: achter een vlag.
  • Rand: achter een vlag.
  • Firefox: niet ondersteund.
  • Safari: niet ondersteund.

Chrome heeft gewerkt aan een reeks nieuwe API's en uitbreidingen op de bestaande setHTML en setHTMLUnsafe die dit probleem oplossen, en introduceert tevens streamingfunctionaliteit.

Deze functies zijn vanaf Chrome 148 klaar voor ontwikkelaarstests met behulp van de vlag chrome://flags/#enable-experimental-web-platform-features en zullen naar verwachting in Chrome 155 worden gelanceerd.

Er zijn methoden om inhoud in te stellen of te vervangen, evenals methoden om inhoud vóór of na bestaande HTML in te voegen. Elke methode heeft stream-equivalenten:

Actie Statisch Streaming
Stel de HTML-inhoud van het element in. setHTML(html, options); streamHTML(options);
Vervang het hele element door deze HTML. replaceWithHTML(html, options); streamReplaceWithHTML(options);
Voeg de HTML toe vóór het element beforeHTML(html, options); streamBeforeHTML(options);
Voeg de HTML toe als eerste kindelement van het element. prependHTML(html, options); streamPrependHTML(options);
Voeg de HTML toe als laatste kindelement van het element. appendHTML(html, options); streamAppendHTML(options);
Voeg de HTML toe na het element afterHTML(html, options); streamAfterHTML(options);
De nieuwe invoeg- en streamingmethoden

Er bestaan ​​ook Unsafe versies, die we zo dadelijk zullen bespreken. Hoewel het er misschien veel lijken te zijn – vooral als je de Unsafe equivalenten meetelt – maakt de consistente naamgeving het duidelijker wat elke methode doet, in vergelijking met de eerder genoemde, losstaande methoden.

De statische versies accepteren nieuwe HTML als een DOM-stringargument, samen met optionele opties:

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

contentElement.setHTML(newHTML);

De streamingversies werken met de Streams API , bijvoorbeeld met een 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();

Of, als alternatief, vanuit een fetch-respons met behulp van pipe chains :

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

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

textStream() handige methode

Browser Support

  • Chrome: 151.
  • Rand: 151.
  • Firefox: niet ondersteund.
  • Safari: niet ondersteund.

Er is ook een handige textStream methode toegevoegd waarmee je direct kunt streamen zonder de tussenliggende TextDecoderStream() stap:

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

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

options

Met het argument options kunt u een aangepaste sanitizer specificeren. default wordt de standaard sanitizerconfiguratie gebruikt. Het wordt als volgt gebruikt:

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

"Onveilige" methoden

Er bestaan ​​ook "onveilige" versies van elk van de API's:

Actie Statisch Streaming
Stel de HTML-inhoud van het element in. setHTMLUnsafe(html,options); streamHTMLUnsafe(options);
Vervang het hele element door deze HTML. replaceWithHTMLUnsafe(html, options); streamReplaceWithHTMLUnsafe(options);
Voeg de HTML toe vóór het element beforeHTMLUnsafe(html, options); streamBeforeHTMLUnsafe(options);
Voeg de HTML toe als eerste kindelement van het element. prependHTMLUnsafe(html, options); streamPrependHTMLUnsafe(options);
Voeg de HTML toe als laatste kindelement van het element. appendHTMLUnsafe(html, options); streamAppendHTMLUnsafe(options);
Voeg de HTML toe na het element afterHTMLUnsafe(html, options); streamAfterHTMLUnsafe(options);
De "onveilige" invoeg- en streamingmethoden

Deze "onveilige" methoden schakelen de sanitizer standaard uit, maar u kunt desgewenst een aangepaste sanitizer specificeren. Deze methoden maken het ook mogelijk om scripts uit te voeren met een optionele runScripts optie, die standaard op false staat.

Net als setHTML is setHTMLUnsafe een bestaande methode, maar de optieparameter runScripts is eraan toegevoegd zodat deze ook gebruikt kan worden bij het uitvoeren van scripts:

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

De formulering "onveilig" in de methode is bedoeld om ontwikkelaars te herinneren aan het potentiële risico en hoe ze scripts eventueel kunnen beveiligen of beperken, en niet om te zeggen dat deze methoden niet gebruikt zouden moeten worden.

Hoe "onveilig" dit is, hangt af van hoe betrouwbaar de invoer is. De statische methoden van het Unsafe werken met zowel DOM String als TrustedHTML als html argumenten en staan ​​ook het gebruik van sanitizers toe. Bij runScript is het echter de bedoeling om scripts toe te staan, vandaar dat er standaard geen sanitizer wordt gebruikt.

Gebruiksvoorbeelden

Deze nieuwe API's maken het voor ontwikkelaars eenvoudiger om HTML aan bestaande pagina's toe te voegen, door nieuwe API's met consistente namen en opties te introduceren. De streaming-API's bieden het voordeel dat er niet gewacht hoeft te worden tot alle nieuwe content beschikbaar is op het platform.

Toepassingsvoorbeelden zijn onder meer:

  • Dynamische streaming van grote contentupdates in Single Page Apps. Zoals eerder vermeld, is een groot nadeel van de huidige SPA-architectuur dat deze niet profiteert van het streamingkarakter van de initiële HTML-ladingen – tot nu toe!
  • Het invoegen van veelvoorkomende content zoals HTML-voetteksten. Met behulp van de JavaScript API's kunt u gedeeltelijke elementen ophalen en in de pagina invoegen, waardoor u profiteert van caching in plaats van ze op elke pagina te herhalen. Gezien de afhankelijkheid van JavaScript voor de werking, moet dit echter alleen worden gebruikt voor content die niet zichtbaar is bij het laden van de pagina.

Dit zijn slechts een paar voorbeelden en we zijn erg benieuwd wat jullie bedenken!

Beperkingen en nuances

Deze nieuwe API's kennen ook een aantal beperkingen en nuances waar je rekening mee moet houden:

  • Integratie van streaming met de Trusted Types API vereist het gebruik van een nieuwe createParserOptions -methode waarmee een sanitizer kan worden geïnjecteerd in elke HTML-instellingbewerking. Zie de uitleg voor meer informatie over de integratie van Trusted Types.
  • Net als bij <template for> kan het verplaatsen van elementen die worden gestreamd, onverwachte gevolgen of streamfouten veroorzaken.
  • streamHTMLUnsafe werkt in veel opzichten meer zoals de hoofdparser, onder andere door <template for> -instructies te verwerken zodra ze aan het hoofddocument worden toegevoegd en door defer scripts uit te stellen tot het einde van de stream.

Standaardisatiestatus

De nieuwere invoeg- en streamingmethoden worden momenteel toegevoegd aan de HTML-standaard , maar worden nog niet door alle browsers ondersteund.

Polyfill

Het Chrome-team heeft een html-setters-polyfill uitgebracht die beschikbaar is op npm , zodat websites deze nieuwe functionaliteit direct kunnen gebruiken, zelfs voordat deze in andere browsers beschikbaar komt.

Merk op dat deze polyfill niet streamt, maar buffert en toepast zodra de verwerking is voltooid. Het is meer een polyfill voor de structuur van de API dan voor de functionaliteit.

Daarnaast is het instellen van veilige content afhankelijk van setHTML en de Sanitizer API , die niet door Safari worden ondersteund.

Gebruik ze allebei samen.

Hoewel dit twee afzonderlijke API's zijn, schuilt de echte kracht in de combinatie ervan. Door nieuwe <template for> -elementen in de HTML te streamen, kunt u verschillende delen van de content dynamisch bijwerken zonder dat u elk onderdeel rechtstreeks hoeft te benaderen met afzonderlijke JavaScript-referenties naar de DOM.

Een eenvoudige paginalading in SPA-stijl kan worden geïmplementeerd door een overzichtspagina met verwerkingsinstructies te laden en vervolgens de sjablonen van elke nieuwe pagina in de HTML te streamen, zodat ze in die verwerkingsinstructies passen.

Er is ongetwijfeld meer potentieel en er zijn meer toepassingsmogelijkheden voor beide API's, dus laat onze (beperkte!) verbeelding je niet tegenhouden. Door gedeeltelijke updates eenvoudiger te maken, kun je de hoeveelheid standaardcode verminderen, updates vereenvoudigen en nieuwe mogelijkheden voor het web ontsluiten!

Chrome werkt nog aan een aantal API's binnen het project Declarative Partial Updates , maar we zijn erg blij dat we deze eerste twee nu al met jullie kunnen delen. We houden jullie op de hoogte en laten het weten wanneer er meer beschikbaar komt.