Skip to content

Commit 8f0e3d4

Browse files
committed
Simplify API: remove active attribute, introduce stand-alone async/buffered/sanitize attributes
1 parent 6ac7371 commit 8f0e3d4

1 file changed

Lines changed: 66 additions & 61 deletions

File tree

fragment-include-explainer.md

Lines changed: 66 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -20,49 +20,32 @@ The proposed [Declarative Out-of-order streaming specification](https://github.c
2020

2121
## Proposed solution
2222

23-
Proposing to extend the `<template>` element to support native, client-side HTML includes and dynamic content updates by introducing the `active` attribute, as well as fetching attributes (`src`, `crossorigin`, `referrerpolicy`, `nonce`, `integrity`, `blocking`).
23+
We propose extending the `<template>` element to support native, client-side HTML includes and dynamic content updates by introducing the `for`, `src`, `async`, `buffered`, and `sanitize` attributes.
2424

2525
### Activation Model and Modes
26-
The operational mode of the `<template>` element is explicitly declared and activated using the `active` attribute
27-
which accepts a space-separated list of configuration tokens (represented as a `DOMTokenList` in JS):
28-
- **`buffered`**: Parses content into a detached buffer and renders it atomically on stream completion.
29-
- **`unsafe`**: Disables sanitization, allowing full HTML fragment parsing and script execution.
30-
- **`async`**: Configures the network fetch (`src` present) to be asynchronous and non-blocking relative to document parsing.
3126

27+
An HTML `<template>` is active if it has a `for` attribute, a `src` attribute, or both. If both attributes are absent, it behaves as a classic inert template.
3228

33-
#### Default `active` Resolution
34-
To determine the template's activation state and delivery/safety modes, the browser resolves the `active` token list using the following ordered algorithm:
35-
36-
1. **If the `active` attribute is explicitly present**:
37-
Use the declared token list (e.g. `active=""` resolves to streaming, sanitized; `active="buffered"` resolves to buffered, sanitized).
38-
2. **Else if the `src` attribute is present**:
39-
Resolve the activation state to **`""`** (streaming, sanitized).
40-
3. **Else if the `for` attribute is present**:
41-
Resolve the activation state to **`"unsafe"`** (streaming, unsanitized, matching existing "patching" behavior).
42-
4. **Otherwise**:
43-
Resolve to **`null`** (inert classic template behavior).
44-
45-
46-
Targeting is controlled via the `for` attribute:
47-
- **Targeted Activation (`for="target-name"`)**:
29+
#### Targeting and Placement
30+
- **Targeted Include (`for="target-name"`)**:
4831
Applies the template content to a targeted range (`<?start name="target-name">...<?end>`) or insertion point (`<?marker name="target-name">`). Content is inserted **before** the `<?end>` or `<?marker>` node.
49-
- **In-place Activation (omitted or empty `for` with active template)**:
50-
Inserts the content in-place at the template's position in the HTML stream.
32+
- **In-place Include (omitted `for` or empty `for=""` / `for`)**:
33+
Inserts the content in-place at the template's position in the HTML stream. If `for` is omitted entirely but `src` is present, it defaults to an in-place include.
5134

5235
```html
53-
<!-- Inert template (legacy behavior, does not render) -->
36+
<!-- Inert template (does not render) -->
5437
<template id="menu-tpl">
5538
<li>Menu Item</li>
5639
</template>
5740

58-
<!-- Active in-place rendering (streaming, sanitized) -->
59-
<template active>
41+
<!-- Active in-place rendering (inline streaming, unsafe by default) -->
42+
<template for>
6043
<p>Renders progressively in-place.</p>
6144
</template>
6245

63-
<!-- Active in-place rendering (buffered, sanitized) -->
64-
<template active="buffered">
65-
<p>Renders atomically once fully parsed.</p>
46+
<!-- Active in-place rendering (buffered, unsafe by default) -->
47+
<template for buffered>
48+
<p>Renders atomically once inline parsing is complete.</p>
6649
</template>
6750

6851
<!-- Targeted rendering (streaming, unsafe by default) -->
@@ -73,76 +56,97 @@ Targeting is controlled via the `for` attribute:
7356
<p>Streams contents directly into the gallery section.</p>
7457
</template>
7558

76-
<!-- Targeted rendering (buffered, sanitized) -->
59+
<!-- Targeted rendering (buffered, sanitized explicitly) -->
7760
<section id="comments">
7861
<?start name="comments-patch">Loading...<?end>
7962
</section>
80-
<template for="comments-patch" active="buffered">
81-
<p>Inserts atomically once comments are fully parsed.</p>
63+
<template for="comments-patch" buffered sanitize>
64+
<p>Inserts atomically once comments are fully parsed, with scripts stripped.</p>
8265
</template>
8366
```
8467

85-
During active non-targeted template processing (streaming or buffered), the browser temporarily attaches the `<template>` element to the DOM at its declared position to act as the parser's insertion anchor. Incoming content is parsed and inserted directly **before** the template element. Once parsing/streaming completes (network EOF or closing tag), the template element is detached and removed, leaving **zero DOM footprint** in the final tree.
68+
During active in-place template processing (streaming or buffered), the browser temporarily attaches the `<template>` element to the DOM at its declared position to act as the parser's insertion anchor. Incoming content is parsed and inserted directly **before** the template element. Once processing completes (network EOF or closing tag), the template element is detached and removed, leaving **zero DOM footprint** in the final tree.
8669

8770
### Resource Fetching and Script Attributes
71+
8872
When the `src` attribute is present, the template fetches its HTML payload over the network.
89-
- `<template active="async" src="fragment.html"></template>`
90-
- Reuses `<script>`'s other network configuration attributes: `blocking`, `nonce`, `crossorigin`, and `referrerpolicy`. Async/non-blocking behavior is controlled directly by the `async` token in the `active` token list.
73+
- **`async` (boolean)**: Configures the network fetch to be asynchronous and non-blocking relative to document parsing. If absent, the fetch is blocking (synchronous include).
74+
- Reuses `<script>`'s other network configuration attributes: `blocking`, `nonce`, `crossorigin`, and `referrerpolicy`.
9175

76+
```html
77+
<!-- Synchronous blocking in-place include (sanitized by default) -->
78+
<template src="header.html"></template>
79+
80+
<!-- Asynchronous non-blocking targeted include (sanitized by default) -->
81+
<div id="content">
82+
<?start name="main-content">Loading...<?end>
83+
</div>
84+
<template for="main-content" src="content.html" async></template>
85+
```
9286

9387
### Buffering vs. Streaming
94-
- **Streaming (Default active mode)**:
95-
If the `buffered` token is absent (e.g. `<template active>`), content is progressively parsed and inserted into the live DOM before the marker/template anchor.
96-
- **Buffered (`active="buffered"`)**:
97-
The browser parses the content directly into the template's own `content` DocumentFragment property. Once parsing completes, the sanitized contents of this DocumentFragment are cloned and inserted in a single batch.
9888

89+
The delivery mode is configured using the boolean `buffered` attribute:
90+
- **Streaming (Default, `buffered` absent)**:
91+
Content is progressively parsed and inserted into the live DOM before the marker/template anchor as network chunks arrive.
92+
- **Buffered (`buffered` present)**:
93+
The browser parses the content directly into the template's own `content` DocumentFragment property. Once parsing completes, the sanitized contents of this DocumentFragment are cloned and inserted in a single atomic update.
9994

10095
```html
10196
<!-- 1. Streaming (Progressive Render) -->
10297
<!-- In-place: elements render as they arrive from network -->
103-
<template active src="feed-stream.html"></template>
98+
<template src="feed-stream.html" async></template>
10499

105100
<!-- Targeted: rows stream progressively into tbody without foster-parenting -->
106101
<table>
107102
<tbody id="table-rows">
108103
<?start name="rows-patch"><tr><td>Loading rows...</td></tr><?end>
109104
</tbody>
110105
</table>
111-
<template for="rows-patch" src="rows.html"></template>
106+
<template for="rows-patch" src="rows.html" async></template>
112107

113108

114109
<!-- 2. Buffered (Atomic Render once complete) -->
115110
<!-- In-place: parsed to template.content first, inserted in one single batch on EOF -->
116-
<template active="buffered" src="dialog-modal.html"></template>
111+
<template src="dialog-modal.html" async buffered></template>
117112

118113
<!-- Targeted: comments block is parsed fully to fragment and inserted atomically -->
119114
<section id="comments-section">
120115
<?start name="comments-patch">Loading comments...<?end>
121116
</section>
122-
<template for="comments-patch" active="buffered" src="comments.html"></template>
117+
<template for="comments-patch" src="comments.html" async buffered></template>
123118
```
124119

125120
### Security & Sanitization
126-
- **Explicitly Activated (`active` present)**: **Sanitized by default**. To disable sanitization and execute scripts, include the `unsafe` token in the `active` token list.
127-
- **Implicitly Activated (`for` present, `active` omitted)**: **Unsafe by default** (implicitly resolves to `active="unsafe"`), matching standard patching behavior.
121+
122+
Security safety is configured via the `sanitize` attribute, which accepts either an empty value (`sanitize` or `sanitize=""`) or `sanitize="unsafe"`.
123+
124+
#### Default Safety Resolution
125+
To optimize security and compatibility, the default safety behavior is determined by the presence of the `src` attribute:
126+
1. **External Includes (`src` is present)**: **Sanitized by default**.
127+
- If `sanitize` is omitted, it defaults to safe sanitization.
128+
- To execute scripts, the author must explicitly opt-out with `sanitize="unsafe"`.
129+
2. **Inline Templates (`src` is absent)**: **Unsafe by default**.
130+
- If `sanitize` is omitted, script execution is allowed (preserving compatibility with standard patching behavior).
131+
- To enable sanitization on inline content, the author must explicitly declare `sanitize`.
128132

129133
```html
130-
<!-- Explicit active: sanitized by default (scripts stripped) -->
131-
<template active src="user-profile.html"></template>
134+
<!-- External: sanitized by default (scripts stripped) -->
135+
<template src="user-profile.html" async></template>
132136

133-
<!-- Explicit active with unsafe token: unsanitized (allows script execution) -->
134-
<template active="unsafe" src="ad.html"></template>
137+
<!-- External with unsafe token: unsanitized (allows script execution) -->
138+
<template src="ad.html" async sanitize="unsafe"></template>
135139

136-
<!-- Explicit active buffered with unsafe token -->
137-
<template active="buffered unsafe" src="modal-widget.html"></template>
140+
<!-- External buffered with unsafe token -->
141+
<template src="modal-widget.html" async buffered sanitize="unsafe"></template>
138142

139-
<!-- Implicit active: unsafe by default (script runs) -->
143+
<!-- Inline: unsafe by default (script runs) -->
140144
<template for="gallery">
141145
<script>alert(1)</script>
142146
</template>
143147

144-
<!-- Implicit active, but sanitized: explicit active (without unsafe) overrides default -->
145-
<template for="gallery" active>
148+
<!-- Inline but sanitized: explicit sanitize attribute overrides default -->
149+
<template for="gallery" sanitize>
146150
<div>User input: <script>alert(1)</script></div>
147151
</template>
148152
```
@@ -151,10 +155,10 @@ When the `src` attribute is present, the template fetches its HTML payload over
151155
To allow granular security configuration for declarative includes, this proposal integrates with Content Security Policy (CSP):
152156

153157
1. **`fragment-src` Directive (New):**
154-
Governs which origins are allowed to serve HTML subresources fetched via `<template active src="url">`. Fallback defaults to `default-src`.
155-
Since standard active templates (without the `unsafe` token) are sanitized by default (scripts stripped), pages can allow a relaxed `fragment-src` policy (e.g. allowing third-party CDNs or CMS domains) without exposing themselves to script-execution vulnerabilities.
158+
Governs which origins are allowed to serve HTML subresources fetched via `<template src="url">`. Fallback defaults to `default-src`.
159+
Since standard active templates (without `sanitize="unsafe"`) are sanitized by default (scripts stripped), pages can allow a relaxed `fragment-src` policy (e.g. allowing third-party CDNs or CMS domains) without exposing themselves to script-execution vulnerabilities.
156160
2. **`script-src` Enforcement:**
157-
If a template includes the `unsafe` token (e.g. `<template active="unsafe" src="...">`), any inline `<script>` tags parsed from the fetched HTML must pass standard `script-src` policies (e.g. nonce or hash checks) to be allowed to execute.
161+
If a template includes `sanitize="unsafe"`, any inline `<script>` tags parsed from the fetched HTML must pass standard `script-src` policies (e.g. nonce or hash checks) to be allowed to execute.
158162

159163
## Performance
160164

@@ -254,10 +258,10 @@ This makes errors or latency difficult to observe, unlike the `<template>` based
254258

255259
10. **Do features in this specification enable new script execution/loading mechanisms?**
256260
Yes. By importing external HTML subresources, the feature allows loading and parsing HTML which may contain scripts.
257-
**Mitigation:** The proposal enforces security-by-default for explicitly activated templates. Explicitly declaring `active` (e.g. `<template active src="...">`) enables HTML sanitization by default, stripping out all script tags and event handler attributes before DOM insertion. To execute scripts, authors must explicitly opt-out of sanitization by including the `unsafe` token in the `active` token list (e.g., `active="unsafe"`).
261+
**Mitigation:** The proposal enforces security-by-default for external resource includes. When `src` is present, HTML sanitization is enabled by default, stripping out all script tags and event handler attributes before DOM insertion. To execute scripts, authors must explicitly opt-out of sanitization by setting `sanitize="unsafe"`.
258262
Furthermore, fetching external templates is governed by Content Security Policy (CSP):
259-
* The new **`fragment-src`** directive controls which origins are allowed to serve HTML payloads for active templates. Because templates are sanitized by default, sites can configure a relaxed `fragment-src` policy for trusted CDN content without allowing script-injection paths.
260-
* If `unsafe` is declared, any inline `<script>` tags loaded from the template must strictly comply with the document's standard **`script-src`** directives (e.g., matching nonce/hash).
263+
* The new **`fragment-src`** directive controls which origins are allowed to serve HTML payloads for active templates. Because external templates are sanitized by default, sites can configure a relaxed `fragment-src` policy for trusted CDN content without allowing script-injection paths.
264+
* If `sanitize="unsafe"` is declared, any inline `<script>` tags loaded from the template must strictly comply with the document's standard **`script-src`** directives (e.g., matching nonce/hash).
261265

262266

263267
11. **Do features in this specification allow an origin to access other devices?**
@@ -270,11 +274,12 @@ This makes errors or latency difficult to observe, unlike the `<template>` based
270274
N/A.
271275

272276
14. **How does this specification distinguish between behavior in first-party and third-party contexts?**
273-
Subresources fetched via `<template active src="...">` are subject to standard Cross-Origin Resource Sharing (CORS) rules. Cross-origin templates require CORS headers to be read.
277+
Subresources fetched via `<template src="...">` are subject to standard Cross-Origin Resource Sharing (CORS) rules. Cross-origin templates require CORS headers to be read.
274278

275279
15. **How do the features in this specification work in the context of a browser’s Private Browsing or Incognito mode?**
276280
Standard subresource caching and partitioning rules apply.
277281

282+
278283
16. **Does this specification have both "Security Considerations" and "Privacy Considerations" sections?**
279284
Yes, these will be integrated into the HTML Standard.
280285

0 commit comments

Comments
 (0)