Skip to content
Open
Changes from 2 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
6ec5ba3
Add declarative out-of-order streaming
foolip Oct 22, 2025
50a4491
Think out loud with TODOs and questions
foolip Oct 22, 2025
97d3cfd
Flesh things out more
foolip Oct 23, 2025
8739f8b
Let shadowrootmode take precedent over contentmethod
foolip Oct 27, 2025
00872de
Add a note about scope's type
foolip Oct 27, 2025
d99f332
Fix incorrect method descriptions
foolip Oct 29, 2025
5c43560
Define templat's content target element-or-null slot
foolip Nov 6, 2025
cec66b6
Flesh out a lot of details (some in the wrong place/order)
foolip Nov 6, 2025
ff83da1
Rewrite again to handle all known issues
foolip Nov 7, 2025
1d1af08
Add an example
foolip Nov 7, 2025
911cd92
Refactors on a plane
foolip Nov 13, 2025
1e56dfb
Drop contentmethod=replace and prepend
foolip Dec 4, 2025
271553e
Attach the <template> on error
foolip Dec 4, 2025
e4946fc
Clarify purpose of body scope hoisting
foolip Dec 4, 2025
521f343
Disallow patching of <script>
foolip Dec 4, 2025
f5a06b1
Introduce "content error" to make errors unrecoverable
foolip Dec 16, 2025
5fe6778
Fix TODOs and typos
foolip Dec 16, 2025
0dbaff6
Rewrite to <template for> with PIs
foolip Mar 6, 2026
61d4ab1
split for on the first #
foolip Mar 9, 2026
3c7abb0
Fix "find marker" algo bugs
foolip Mar 9, 2026
3382877
Add null check for end node
foolip Mar 9, 2026
34f4e4a
assert that start is not null
foolip Mar 9, 2026
168c4c8
Use template contents when scope is a template
foolip Mar 9, 2026
f5ff8d5
Restore adjusted insertion location fixups for DSD
foolip Mar 9, 2026
36ae3a5
Add note about nested <template for>
foolip Mar 12, 2026
862f5f2
Drop the marker attribute
foolip Mar 18, 2026
ce2772a
Compare PI target case-sensitively
foolip Mar 18, 2026
59580a6
Require <template for> to not be the empty string
foolip Mar 19, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 102 additions & 2 deletions source
Original file line number Diff line number Diff line change
Expand Up @@ -67863,6 +67863,7 @@ not-slash = %x0000-002E / %x0030-10FFFF
<dd><span data-x="concept-content-nothing">Nothing</span> (for clarification, <a href="#template-example">see example</a>).</dd>
<dt><span data-x="concept-element-attributes">Content attributes</span>:</dt>
<dd><span>Global attributes</span></dd>
<dd><code data-x="attr-template-contentmethod">contentmethod</code></dd>
<dd><code data-x="attr-template-shadowrootmode">shadowrootmode</code></dd>
<dd><code data-x="attr-template-shadowrootdelegatesfocus">shadowrootdelegatesfocus</code></dd>
<dd><code data-x="attr-template-shadowrootclonable">shadowrootclonable</code></dd>
Expand All @@ -67879,6 +67880,7 @@ interface <dfn interface>HTMLTemplateElement</dfn> : <span>HTMLElement</span> {
[<span>HTMLConstructor</span>] constructor();

readonly attribute <span>DocumentFragment</span> <span data-x="dom-template-content">content</span>;
[<span>CEReactions</span>] attribute DOMString <span data-x="dom-template-contentmethod">contentMethod</span>;
[<span>CEReactions</span>] attribute DOMString <span data-x="dom-template-shadowrootmode">shadowRootMode</span>;
[<span>CEReactions</span>, <span data-x="xattr-Reflect">Reflect</span>] attribute boolean <dfn attribute for="HTMLTemplateElement" data-x="dom-template-shadowrootdelegatesfocus">shadowRootDelegatesFocus</dfn>;
[<span>CEReactions</span>, <span data-x="xattr-Reflect">Reflect</span>] attribute boolean <dfn attribute for="HTMLTemplateElement" data-x="dom-template-shadowrootclonable">shadowRootClonable</dfn>;
Expand All @@ -67894,6 +67896,40 @@ interface <dfn interface>HTMLTemplateElement</dfn> : <span>HTMLElement</span> {

<p>In a rendering, the <code>template</code> element <span>represents</span> nothing.</p>

<p>The <dfn element-attr for="template"><code
data-x="attr-template-contentmethod">contentmethod</code></dfn> content attribute is an
<span>enumerated attribute</span> with the following keywords and states:</p>

<table>
<thead>
<tr>
<th>Keyword
<th>State
<th>Brief description
<tbody>
<tr>
<td><dfn attr-value for="template/contentmethod"><code data-x="attr-contentmethod-replace">replace</code></dfn>
<td><dfn data-x="attr-contentmethod-replace-state">Replace</dfn>
<td>Replace the target element itself.
<tr>
<td><dfn attr-value for="template/contentmethod"><code data-x="attr-contentmethod-replace-children">replace-children</code></dfn>
<td><dfn data-x="attr-contentmethod-replace-children-state">Replace Children</dfn>
<td>Replace the children of the target element.
<tr>
<td><dfn attr-value for="template/contentmethod"><code data-x="attr-contentmethod-append">append</code></dfn>
<td><dfn data-x="attr-contentmethod-append-state">Append</dfn>
<td>Append after the target element.
<tr>
Comment thread
foolip marked this conversation as resolved.
Outdated
<td><dfn attr-value for="template/contentmethod"><code data-x="attr-contentmethod-prepend">prepend</code></dfn>
<td><dfn data-x="attr-contentmethod-prepend-state">Prepend</dfn>
<td>Prepend before the target element.
</table>

<p>The <code data-x="attr-template-contentmethod">contentmethod</code> attribute's <i
data-x="invalid value default">invalid value default</i> and <i data-x="missing value
default">missing value default</i> are both the <dfn
data-x="attr-contentmethod-none-state">None</dfn> state.</p>

<p>The <dfn element-attr for="template"><code
data-x="attr-template-shadowrootmode">shadowrootmode</code></dfn> content attribute is an
<span>enumerated attribute</span> with the following keywords and states:</p>
Expand Down Expand Up @@ -68075,6 +68111,13 @@ interface <dfn interface>HTMLTemplateElement</dfn> : <span>HTMLElement</span> {
not a <code>ShadowRoot</code> node; otherwise null.</p>
</div>

<div algorithm>
<p>The <dfn attribute for="HTMLTemplateElement"><code
data-x="dom-template-contentmethod">contentMethod</code></dfn> IDL attribute must
<span>reflect</span> the <code data-x="attr-template-contentmethod">contentmethod</code> content
attribute, <span>limited to only known values</span>.</p>
</div>

<div algorithm>
<p>The <dfn attribute for="HTMLTemplateElement"><code
data-x="dom-template-shadowrootmode">shadowRootMode</code></dfn> IDL attribute must
Expand Down Expand Up @@ -139403,6 +139446,31 @@ dictionary <dfn dictionary>StorageEventInit</dfn> : <span>EventInit</span> {
<var>element</var>:</p>

<ol>
<!-- Either here and before every other call to "adjusted insertion location", or maybe inside
"adjusted insertion location", adjust the insertion location based on contentmethod and the
first child element of the template. -->
<li>
<p>contentmethod handling:</p>

<ol>
<li><p>If <var>element</var> has a contentname attribute and is being inserted into a template
element with a valid contentmethod attribute, find the target element with the same namespace,
localName, and a contentname attribute with the same value.</p></li>

<li><p>TODO: is there any whitespace stripping in contentname attribute values?</p></li>
Comment thread
foolip marked this conversation as resolved.
Outdated

<li><p>If the template element is in <code>body</code>, instead search the whole document so
that things in <code>head</code> can be patched.</p></li>

<li><p>Return if the target element wasn't found</p></li>

<li><p>Depending on the contentmethod state, remove existing nodes and update the insertion point.</p></li>

<li><p>Question: do we adjust the insertion point simply by setting <var>adjusted insertion location</var>,
Comment thread
foolip marked this conversation as resolved.
Outdated
or is there other bookkeeping that's needed here?</p></li>
</ol>
</li>

<li><p>Let the <var>adjusted insertion location</var> be the <span>appropriate place for
inserting a node</span>.</p></li>

Expand Down Expand Up @@ -140196,6 +140264,10 @@ document.body.appendChild(text);
<p>If any of the following are false:</p>

<ul>
<li><var>templateStartTag</var>'s <code
data-x="attr-template-contentmethod">contentmethod</code> is not in the <span
data-x="attr-contentmethod-none-state">None</span> state;</li>

<li><var>templateStartTag</var>'s <code
data-x="attr-template-shadowrootmode">shadowrootmode</code> is not in the <span
data-x="attr-shadowrootmode-none-state">None</span> state;</li>
Expand All @@ -140208,11 +140280,26 @@ document.body.appendChild(text);
open elements</span>,</li>
</ul>

<p>then <span>insert an HTML element</span> for the token.</p>
<p>then <span>insert an HTML element</span> for the token and return.</p>
</li>

<li>
<p>Otherwise:</p>
<p>If <var>templateStartTag</var>'s <code
data-x="attr-template-contentmethod">contentmethod</code> is not in the <span
data-x="attr-contentmethod-none-state">None</span> state:</p>

<ol>
<li><p>TODO: what to we need to do so that elements are inserted into the template element
and redirected by our pre-insertion steps? We need to undo whatever it is that causes nodes
to be inserted into the DocumentFragment normally.</p></li>
</ol>
Comment thread
foolip marked this conversation as resolved.
Outdated
</li>

<li>
<!-- TODO: is it OK if both of these branches run? If not, which one wins? -->
Comment thread
foolip marked this conversation as resolved.
Outdated
<p>If <var>templateStartTag</var>'s <code
data-x="attr-template-shadowrootmode">shadowrootmode</code> is not in the <span
data-x="attr-shadowrootmode-none-state">None</span> state:</p>

<ol>
<li><p>Let <var>declarativeShadowHostElement</var> be <span>adjusted current
Expand Down Expand Up @@ -152714,6 +152801,19 @@ interface <dfn interface>External</dfn> {
<td> Whether the element is editable
<td> "<code data-x="">true</code>"; "<code data-x="">plaintext-only</code>";
"<code data-x="">false</code>"
<tr>
<th> <code data-x="">contentmethod</code>
<td> <code data-x="attr-template-contentmethod">template</code>
<td> Enables out-of-order streaming <!-- TODO better words -->
<td> "<code data-x="attr-contentmethod-replace">replace</code>";
"<code data-x="attr-contentmethod-replace-children">replace-children</code>";
"<code data-x="attr-contentmethod-append">append</code>";
"<code data-x="attr-contentmethod-prepend">prepend</code>"
<tr>
<th> <code data-x="">contentname</code>
<td> <span data-x="attr-id">HTML elements</span>
<td> Unique string to target what contentmethod affects <!-- TODO better words -->
<td> <a href="#attribute-text">Text</a>*
<tr>
<th> <code data-x="">controls</code>
<td> <code data-x="attr-media-controls">audio</code>;
Expand Down