Skip to content
Open
Changes from all commits
Commits
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
242 changes: 236 additions & 6 deletions source
Original file line number Diff line number Diff line change
Expand Up @@ -13894,6 +13894,7 @@ https://software.hixie.ch/utilities/js/live-dom-viewer/?%3C%21DOCTYPE%20HTML%3E%
<li><code data-x="attr-autocorrect">autocorrect</code></li>
<li><code data-x="attr-fe-autofocus">autofocus</code></li>
<li><code data-x="attr-contenteditable">contenteditable</code></li>
<li><code data-x="attr-contentname">contentname</code></li>
<li><code data-x="attr-dir">dir</code></li>
<li><code data-x="attr-draggable">draggable</code></li>
<li><code data-x="attr-enterkeyhint">enterkeyhint</code></li>
Expand Down Expand Up @@ -67863,6 +67864,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 +67881,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 +67897,44 @@ 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-children">replace-children</code></dfn>
<td><dfn data-x="attr-contentmethod-replace-children-state">Replace Children</dfn>
<td>Replace the child nodes 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 child nodes to 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="htmlsvg-global"><code data-x="attr-contentname">contentname</code></dfn>
attribute value points to the target for template contentmethod, like an ID attribute.</p>
<!-- TODO better words, and should this be in another section since it's not for <template>? -->

<p>If specified, the <code data-x="attr-contentname">contentname</code> attribute value must equal
the <code data-x="attr-contentname">contentname</code> of another element in the same
<span>tree</span>.</p>
<!-- TODO: make this non-symmetrical and matching the processing model -->

<p>Each element has an associated element-or-null <dfn>content target</dfn>, which is initially
null.</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 +68116,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 @@ -68159,6 +68207,62 @@ interface <dfn interface>HTMLTemplateElement</dfn> : <span>HTMLElement</span> {
</div>


<div class="example">

<p>In this example, a <code>template</code> element with a <code
data-x="attr-template-contentmethod">contentmethod</code> attribute is used to stream a docuemnt
out-of-order, sending fast static content first and recommendations computed async as they become
available on the server.</p>

<pre><code class="html">&lt;!DOCTYPE html>
&lt;html lang="en">
&lt;head>
&lt;title>Async recommendation engine&lt;/title>
&lt;style>
aside {
/* position the aside where it can grow without causing layout shift or obscuring other content */
}
aside:has(.placeholder) {
/* style the placeholder content */
}
&lt;/style>
&lt;/head>
&lt;body>
&lt;h1>How to train your cat&lt;/h1>
&lt;p>Set realistic goals and don't expect your cat to make a perfect cup of tea
on the first try.&lt;/p>
&lt;aside contentname="recommended">
&lt;p>Recommended reading:&lt;/p>
&lt;ul class="placeholder">
&lt;li>...&lt;/li>
&lt;li>...&lt;/li>
&lt;li>...&lt;/li>
&lt;/ul>
&lt;/aside>
&lt;p>...&lt;/p>
&lt;p>Now sit back and enjoy your tea with your cat.&lt;/p>

&lt;!-- The server has a potentially long delay at this point. --&gt;

&lt;template contentmethod="replace-children">
&lt;aside contentname="recommended">
&lt;p>Recommended reading:&lt;/p>
&lt;ul>
&lt;li>Cat or butler, which is right for you?&lt;/li>
&lt;li>Rewarding good cat behavior&lt;/li>
&lt;li>Kettles considered harmful&lt;/li>
&lt;/ul>
&lt;/aside>
&lt;/template>
&lt;/body>
&lt;/html></code></pre>

<p>The <code>aside</code> element inside the <code>template</code> replaces the original
<code>aside</code>, and since the new content does not use <code
data-x="">class="placeholder"</code>, the placeholder styling no longer applies.</p>
</div>



<div w-nodev>

Expand Down Expand Up @@ -139261,9 +139365,17 @@ dictionary <dfn dictionary>StorageEventInit</dfn> : <span>EventInit</span> {
</li>

<li>
<p>If the <var>adjusted insertion location</var> is inside a <code>template</code>
element, let it instead be inside the <code>template</code> element's <span>template
contents</span>, after its last child (if any).</p>
<p>If <var>adjusted insertion location</var> is inside an element whose <span>content
target</span> is non-null:</p>

<ol>
<li><p>Let <var>element</var> be that element.</p></li>

<li><p><span>Assert</span>: <var>current node</var> is a <code>template</code> element.</p></li>

<li><p>Set <var>adjusted insertion location</var> to inside <var>element</var>'s <var>content
target</var>, after its last child (if any).</p></li>
</ol>
</li>

<li>
Expand Down Expand Up @@ -139413,6 +139525,96 @@ dictionary <dfn dictionary>StorageEventInit</dfn> : <span>EventInit</span> {
algorithm</span>, then push a new <span>element queue</span> onto <var>element</var>'s
<span>relevant agent</span>'s <span>custom element reactions stack</span>.</p></li>

<li>
<p>If <var>element</var> has a <code data-x="attr-contentname">contentname</code> attribute
set to a non-empty value and <var>adjusted insertion location</var> is inside a
<code>template</code> element which is not <span>connected</span> and whose <code
data-x="attr-template-contentmethod">contentmethod</code> attribute is not in the <span
data-x="attr-contentmethod-none-state">None</span> state:</p>

<ol>
<li><p>Let <var>template</var> be that <code>template</code> element.</p></li>

<li><p>Let <var>target</var> be null.</p></li>

<li>
<p>If <var>element</var> is not a <code>script</code> element:</p>

<p class="note">Targeting <code>script</code> elements is not allowed because inserting
a text node into a <code>script</code> element will not execute the script if the
<code>script</code> element is <span>already started</span>. Inserting a new
<code>script</code> element will reliably execute the script.</p>

<ol>
<li>
<p>Let <var>scope</var> be the second-to-bottommost element on the <span>stack of open
elements</span>.</p>

<p class="note">The bottommost node (the <span>current node</span>) is <var>template</var>
and the node above is what would have been <var>template</var>'s parent if it was
inserted.</p>

<p class="note">In the <span>fragment case</span>, <var>scope</var> can be the root
<code>html</code> element of the temporary document. This makes it possible for <code
data-x="attr-template-contentmethod">contentmethod</code> and <code
data-x="attr-contentname">contentname</code> to modify already-parsed content in the
fragment.</p>
</li>

<li>
<p>If <var>scope</var> is <span>the body element</span> of its <span>node document</span>,
set <var>scope</var> to its parent.</p>

<p class="note">This is to support targeting <code>head</code> with a <code>template</code>
inside <code>body</code>.</p>
</li>

<li><p>Set <var>target</var> to the first <span>descendant</span> of <var>scope</var> in
<span>tree order</span> with a <code data-x="attr-contentname">contentname</code> attribute
value equal to that of <var>element</var>, or null if there is no such element.</p></li>
</ol>
</li>

<li>
<p>If <var>target</var> is an element with the same local name and namespace as
<var>element</var>:</p>

<ol>
<li><p>Set <var>element</var>'s <span>content target</span> to <var>target</var>.</p></li>

<li><p>If <var>template</var>'s <code
data-x="attr-template-contentmethod">contentmethod</code> attribute is in the <span
data-x="attr-contentmethod-replace-children-state">Replace Children</span> state, then
remove <var>target</var>'s children from <var>target</var>.</p></li>
</ol>
</li>

<li>
<p>Otherwise:</p>

<ol>
<li><p><span>Assert</span>: <var>template</var> is the <span>current node</span>.</p></li>

<li><p>Pop the <span>current node</span> off the <span>stack of open
elements</span>.</p></li>

<li><p>Run <span>insert an element at the adjusted insertion location</span> with
<var>template</var>.</p></li>

<li>
<p>Push <var>template</var> onto the <span>stack of open elements</span>.</p>

<p class="note">The above steps undo the effect of the <i>onlyAddToElementStack</i> argument
from the <span>insert a foreign element</span> call that created <var>template</var>,
inserting it where it would have been inserted otherwise. This is to signal an error.
Because <var>template</var> is now <span>connected</span>, any further elements with the
<code data-x="attr-contentname">contentname</code> attribute are treated as any other
content.</p>
</ol>
</li>
</ol>
</li>

<li><p>Insert <var>element</var> at the <var>adjusted insertion location</var>.</p></li>

<li><p>If the parser was not created as part of the <span>HTML fragment parsing
Expand Down Expand Up @@ -140196,9 +140398,13 @@ 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; or</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>
data-x="attr-shadowrootmode-none-state">None</span> state; or</li>

<li><var>document</var>'s <span
data-x="concept-document-allow-declarative-shadow-roots">allow declarative shadow
Expand All @@ -140208,11 +140414,13 @@ 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-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 @@ -140289,6 +140497,17 @@ document.body.appendChild(text);
</li>
</ol>
</li>

<li>
<p>Otherwise, 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><span>Insert a foreign element</span> for <var>templateStartTag</var>, with <span>HTML
namespace</span> and true.</p></li>
</ol>
</li>
</ol>
</dd>

Expand Down Expand Up @@ -152714,6 +152933,17 @@ 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-children">replace-children</code>";
"<code data-x="attr-contentmethod-append">append</code>"
<tr>
<th> <code data-x="">contentname</code>
<td> <span data-x="attr-contentname">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