HTML Template For

Planted 02026-09-04

A browser-native primitive for declarative, out-of-order HTML streaming.

A server often knows some parts of a page before it knows other parts.

Imagine a product page. The server can produce the header, product description, reviews, and footer immediately. The price near the top depends on a slower database request.

Ordinary HTML streaming creates a problem. HTML arrives in source order. If the server waits for the price before continuing, the browser also waits for everything that follows the price.

Frameworks such as React and Svelte work around this problem with out-of-order streaming. They send a placeholder first. When the slow content becomes available, they send that content later, often together with JavaScript that moves the content into the correct earlier position in the DOM. (GitHub)

WHATWG pull request #11818 adds a native HTML mechanism for doing that patching without requiring JavaScript to move the HTML. The pull request was merged into the HTML Living Standard on August 20, 2026. (github.com)

The basic idea

The server first sends a named marker at the location where content should eventually appear:

<ul>
  <?marker name="results"?>
</ul>

The server can then continue sending the rest of the page immediately.

Later, when the server has computed the results, it sends:

<template for="results">
  <li>Result A</li>
  <li>Result B</li>
</template>

The for="results" value matches the name="results" value.

When the HTML parser encounters that <template for="results">, it finds the earlier marker. The parser inserts the <li> elements at that marker’s location. The marker is then removed. The final DOM is effectively:

<ul>
  <li>Result A</li>
  <li>Result B</li>
</ul>

The important point is that the second piece of HTML appeared later in the network response but earlier in the final DOM. That is what “out-of-order streaming” means here. (HTML Living Standard)

Replacing placeholder content

The feature also supports a range instead of a single insertion point.

For example:

<section>
  <h2>Recommendations</h2>

  <?start name="recommendations"?>
  <p>Loading recommendations…</p>
  <?end>
</section>

<!-- More of the page can be sent here. -->

<template for="recommendations">
  <ul>
    <li>Article A</li>
    <li>Article B</li>
  </ul>
</template>

When the browser reaches the <template>, it finds:

<?start name="recommendations"?>

and the corresponding:

<?end>

The browser removes the nodes between those two processing instructions. In this example, it removes:

<p>Loading recommendations…</p>

The parser then inserts the <template> content in that location. When the patch finishes, the start and end processing instructions are also removed. (HTML Living Standard)

This gives the user useful placeholder content immediately and replaces that placeholder when the real content arrives.

What <?marker>, <?start>, and <?end> actually are

These are processing instructions, represented in the DOM by ProcessingInstruction nodes. They are not HTML elements, custom elements, or comments.

The final design introduced three relevant forms:

<?marker name="x"?>

marks one insertion point.

<?start name="x"?>
...
<?end?>

marks a range that can be replaced.

And:

<template for="x">
  ...
</template>

provides the replacement content. The for value must match the name value of the <?marker> or <?start> processing instruction. (HTML Living Standard)

An important detail is that <?end> does not need the name. The parser finds the corresponding end processing instruction from the structure of the sibling nodes. Nested start/end ranges are accounted for when finding that end. If the parser finds a <?start> but no corresponding <?end>, the specification treats the range as extending from the start marker to the end of that marker’s parent. (HTML Living Standard)

This is more than <template> plus automatic appendChild()

A normal <template> stores its HTML in an inert DocumentFragment. Its contents do not become part of the rendered document until JavaScript explicitly inserts them.

A successful <template for> behaves differently while the HTML parser is running.

The parser identifies the earlier target and routes the nodes that it parses inside <template for> to that target. In other words, those nodes become part of the earlier DOM location instead of simply remaining as inert template contents. (HTML Living Standard)

That distinction is important for streaming. A server can produce something like:

<template for="feed">
  <article>...</article>

flush those bytes, then continue producing more articles. The parser can place the parsed nodes at the target as the response arrives. The server does not need to construct the complete replacement first and then run JavaScript afterward.

If the browser cannot find the requested marker, the patch does not occur. The <template> behaves as an ordinary template, so its contents remain hidden rather than appearing at an unintended location. (MDN Web Docs)

Why this matters

Before this feature, a framework that wanted this behavior commonly had to send something conceptually similar to:

<template id="chunk">...</template>

<script>
  // Find the earlier placeholder.
  // Move the template contents there.
  // Remove the placeholder.
</script>

The browser already has an HTML parser that knows how to construct the DOM. This proposal moves the basic patching operation into HTML itself:

<template for="target">
  ...
</template>

So the server can describe where the HTML belongs, and the browser performs the insertion.

That has several consequences:

  • The initial response can display fast content without waiting for slower server work.
  • Slow content can arrive later without forcing all subsequent HTML to wait.
  • The server does not need an inline JavaScript program solely to move streamed HTML into its final location.
  • Frameworks can potentially use a browser primitive instead of inventing their own DOM-patching protocol.
  • Placeholder content can remain visible until its replacement starts arriving. (GitHub)

What this does not replace

This feature does not replace React, Server Components, hydration, client-side routing, or JavaScript in general.

It solves a much narrower problem:

Given HTML that arrives later in the same stream, insert that HTML into an earlier location in the document.

It does not determine how the server fetches the data. It does not make components interactive. It does not restore JavaScript state. It does not hydrate event handlers. It does not provide a component model.

A framework such as React could potentially use this mechanism as one lower-level primitive for streaming HTML while continuing to use its own mechanisms for hydration and application state.

Also, “no JavaScript required for patching” does not mean scripts cannot occur inside a patch. The design explicitly allows parser-inserted scripts inside a patch to execute according to the normal HTML parsing rules. (GitHub)

There are deliberate limits on where a patch can reach

A <template for> does not receive unrestricted access to the entire DOM.

Marker lookup is scoped to prevent one component from unexpectedly patching unrelated parts of the page. The mechanism is also tree-scoped, so a patch does not simply cross a shadow-root boundary.

There is one useful special case. A <template for> that is a direct child of <body> can target markers in <head>. This allows streamed HTML to update elements such as <title> after slower server work finishes. (HTML Living Standard)

The shortest accurate description

You can think of the feature as adding a native HTML command with this meaning:

Earlier in the document:

    Put a named insertion point or replacement range here.

Later in the same HTML stream:

    The following HTML belongs at that named location.

Browser:

    Parse the later HTML directly into the earlier location.

One important production caveat

The specification has been merged, but browser support is not yet universal.

As of September 4, 2026, Web Platform DX reports support in Chrome 150+ and Edge 150+. Firefox and Safari do not yet support <template for>, so the feature is classified as having limited availability. (Baseline)

So the significance of PR #11818 is not “all websites can immediately remove their streaming JavaScript.” Its significance is that the HTML standard now defines a browser-native primitive for declarative, out-of-order HTML streaming, and browser implementations can converge on that primitive.