Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Define the <selectedcontent> element #10633

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
241 changes: 238 additions & 3 deletions source
Original file line number Diff line number Diff line change
Expand Up @@ -3230,6 +3230,7 @@ a.setAttribute('href', 'https://example.com/'); // change the content attribute
<li>The <dfn data-x-href="https://dom.spec.whatwg.org/#concept-tree-child" data-x="concept-tree-child">child</dfn> concept</li>
<li>The <dfn data-x-href="https://dom.spec.whatwg.org/#concept-tree-root">root</dfn> and <dfn data-x-href="https://dom.spec.whatwg.org/#concept-shadow-including-root">shadow-including root</dfn> concepts</li>
<li>The <dfn data-x-href="https://dom.spec.whatwg.org/#concept-tree-inclusive-ancestor">inclusive ancestor</dfn>,
<dfn data-x-href="https://dom.spec.whatwg.org/#concept-tree-ancestor">ancestor</dfn>,
<dfn data-x-href="https://dom.spec.whatwg.org/#concept-tree-descendant">descendant</dfn>,
<dfn data-x="concept-shadow-including-ancestor" data-x-href="https://dom.spec.whatwg.org/#concept-shadow-including-ancestor">shadow-including ancestor</dfn>,
<dfn data-x-href="https://dom.spec.whatwg.org/#concept-shadow-including-descendant">shadow-including descendant</dfn>,
Expand Down Expand Up @@ -3343,6 +3344,8 @@ a.setAttribute('href', 'https://example.com/'); // change the content attribute
<li><dfn data-x-href="https://dom.spec.whatwg.org/#abortcontroller-signal-abort">signal abort</dfn></li>
<li><dfn data-x="AbortSignal-add" data-x-href="https://dom.spec.whatwg.org/#abortsignal-add">add</dfn></li>
<li>The <dfn data-x-href="https://dom.spec.whatwg.org/#concept-element-attributes-get-by-name">get an attribute by name</dfn> algorithm</li>
<li>The <dfn data-x-href="https://dom.spec.whatwg.org/#concept-node-ensure-pre-insertion-validity">ensure pre-insertion validity</dfn> algorithm</li>
<li>The <dfn data-x-href="https://dom.spec.whatwg.org/#converting-nodes-into-a-node">convert nodes into a node</dfn> algorithm</li>
</ul>

<p>The following features are defined in <cite>UI Events</cite>: <ref>UIEVENTS</ref></p>
Expand Down Expand Up @@ -53198,6 +53201,8 @@ You cannot submit this form when the field is incorrect.</samp></pre>
<dd><span>Phrasing content</span>, but there must be no <span>interactive content</span>
descendant and no descendant with the <code data-x="attr-tabindex">tabindex</code> attribute
specified.</dd>
<dd>If the element is the first child of a <code>select</code> element, then it may also have
zero or one <code>selectedcontent</code> element.</dd>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does not seem accurate as it may also have other content in such cases, right? Otherwise, what would be the point of this element.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the previous line about phrasing content also applies so that you can have phrasing content and a selectedcontent element. I added the word "also" to make this more clear. I could also combine this with the previous <dd>, what do you think?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think in element definitions thus far the dd elements are mutually exclusive. Not additive.

<dt><span data-x="concept-element-attributes">Content attributes</span>:</dt>
<dd><span>Global attributes</span></dd>
<dd><code data-x="attr-fe-disabled">disabled</code></dd>
Expand Down Expand Up @@ -53511,6 +53516,10 @@ interface <dfn interface>HTMLSelectElement</dfn> : <span>HTMLElement</span> {
element, and all the <code>option</code> element children of all the <code>optgroup</code> element
children of the <code>select</code> element, in <span>tree order</span>.</p>

<p>Every <code>select</code> element has <dfn>descendant <code>selectedcontent</code>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like the repetition of the class name in its member. I would also continue to markup selectedcontent I think.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I changed it to descendant <code>selectedcontent</code> elements.

elements</dfn>, which is a <span>list</span> of <code>selectedcontent</code> elements, initially
« ».</p>

<p>The <dfn element-attr for="select"><code data-x="attr-select-required">required</code></dfn>
attribute is a <span>boolean attribute</span>. When specified, the user will be required to select
a value before submitting the form.</p>
Expand Down Expand Up @@ -53662,6 +53671,18 @@ interface <dfn interface>HTMLSelectElement</dfn> : <span>HTMLElement</span> {
<ol>
<li>Set the <code>select</code> element's <span>user validity</span> to true.</li>

<li><p>Let <var>option</var> be the first element in the <code>select</code>'s <span
data-x="concept-select-option-list">list of options</span> which has its <span
data-x="concept-option-selectedness">selectedness</span> set to true if any such
<code>option</code> exists, otherwise null.</p></li>

<li><p>If <var>option</var> is null, then for each <var>selectedcontent</var> of the
<code>select</code>'s <span>descendant <code>selectedcontent</code> elements</span>, run
<span>clear a selectedcontent</span> given <var>selectedcontent</var>.</p></li>

<li><p>Otherwise, run <span>maybe clone an option into selectedcontent</span> given
<var>option</var>.</p></li>

<li><p><span data-x="concept-event-fire">Fire an event</span> named <code
data-x="event-input">input</code> at the <code>select</code> element, with the <code
data-x="dom-Event-bubbles">bubbles</code> and <code data-x="dom-Event-composed">composed</code>
Expand Down Expand Up @@ -54363,6 +54384,47 @@ interface <dfn interface>HTMLOptionElement</dfn> : <span>HTMLElement</span> {

</div>

<p>To get the <dfn>option element ancestor select</dfn> given an <code>option</code>
<var>option</var>:</p>

<ol>
<li>
<p>For each <var>ancestor</var> of <var>option</var>'s <span
data-x="ancestor">ancestors</span>:</p>

<ol>
<li><p>If <var>ancestor</var> is a <code>select</code>, then return
<var>ancestor</var>.</p></li>
</ol>
</li>

<li><p>Return null.</p></li>
</ol>

<p>To <dfn>maybe clone an option into selectedcontent</dfn>, given an <code>option</code>
<var>option</var>:</p>

<ol>
<li>
<p>If all of the following conditions are true:</p>

<ul>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we only support a single selectedcontent element, why do this?

<li><p><var>option</var> has a non-null <span>option element ancestor select</span>;</p></li>

<li><p><var>option</var>'s <span>option element ancestor select</span> does not have the <code
data-x="attr-select-multiple">multiple</code> attribute;</p></li>

<li><p><var>option</var>'s <span data-x="concept-option-selectedness">selectedness</span>
josepharhar marked this conversation as resolved.
Show resolved Hide resolved
is true,</p></li>
</ul>

<p>then for each <var>selectedcontent</var> of <var>option</var>'s <span>option element
ancestor select</span>'s <span>descendant <code>selectedcontent</code> elements</span>, run
<span>clone an option into a selectedcontent</span> given <var>option</var> and
<var>selectedcontent</var>.</p>
</li>
</ol>

<dl class="domintro">
<dt><code data-x=""><var>option</var>.<span subdfn data-x="dom-option-selected">selected</span></code></dt>

Expand Down Expand Up @@ -56023,6 +56085,156 @@ interface <dfn interface>HTMLLegendElement</dfn> : <span>HTMLElement</span> {

</div>

<h4>The <dfn element><code>selectedcontent</code></dfn> element</h4>

<dl class="element">
<dt><span data-x="concept-element-categories">Categories</span>:</dt>
<dd>None.</dd>
<dt><span data-x="concept-element-contexts">Contexts in which this element can be used</span>:</dt>
<dd>As a descendant of a <code>button</code> element which is a child of a <code>select</code>
element.</dd>
<dt><span data-x="concept-element-content-model">Content model</span>:</dt>
<dd><span data-x="concept-content-nothing">Nothing</span>.</dd>
<dt><span data-x="concept-element-attributes">Content attributes</span>:</dt>
<dd><span>Global attributes</span></dd>
<dt><span
data-x="concept-element-accessibility-considerations">Accessibility considerations</span>:</dt>
<dd><a href="https://w3c.github.io/html-aria/#el-selectedcontent">For authors</a>.</dd>
<dd><a href="https://w3c.github.io/html-aam/#el-selectedcontent">For implementers</a>.</dd>
<dt><span data-x="concept-element-dom">DOM interface</span>:</dt>
<dd w-nodev>
<pre><code class="idl">[Exposed=Window]
interface <dfn interface>HTMLSelectedContentElement</dfn> : <span>HTMLElement</span> {
[<span>HTMLConstructor</span>] constructor();
};</code></pre>
</dd>
<dd w-dev>Uses <code>HTMLSelectedContentElement</code>.</dd>
</dl>

<p>The <code>selectedcontent</code> element reflects the contents of a <code>select</code>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I worry that implementers will look at this and not implement the actual algorithm. Perhaps we can make this web developer edition only or turn it into a note or something?

element's currently selected <code>option</code> element. <code>selectedcontent</code> elements can
be used to declaratively show the selected <code>option</code> element's contents within the
<code>select</code>'s <code>button</code>, with alternate rendering based on different selectors
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a select element*

(but this also doesn't seem entirely true as their parent has to be button and the parent of the button has to be a select)

in the author's stylesheet.</p>

<p>Every time the selected <code>option</code> of a <code>select</code> switches from one option
to another, the <code>selectedcontent</code> element removes all of its children and replaces them
with a new cloned copy of the DOM structure of the <code>select</code>'s selected
<code>option</code> element.</p>

<p><code>selectedcontent</code> elements become associated with <code>select</code> elements when
the <code>selectedcontent</code> is a <span>descendant</span> of the <code>select</code>.</p>

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you need to specify order.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I don't know? The children member is an ordered set, and I think we can just iterate over ordered sets normally, right? Just like the children DOM getter doesn't specify the order of the collection returned: https://dom.spec.whatwg.org/#dom-parentnode-children.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh right. I forgot I made that change at some point and was thinking about an earlier definition of child.

<p>To <dfn>clone an option into a selectedcontent</dfn>, given an <code>option</code> element
<var>option</var> and a <code>selectedcontent</code> element <var>selectedcontent</var>:</p>

<ol>
<li><p>Let <var>nodes</var> be « ».</p></li>

<li>
<p>For each <var>child</var> of <var>option</var>'s <span
data-x="concept-tree-child">children</span>:</p>

<ol>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: this feels like it should be the result of running or the result of <span> converting

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe for readability/clarity this variable could be documentFragment?

<li><p>Let <var>childClone</var> be the result of running <span
data-x="concept-node-clone">clone</span> given <var>child</var>, null, true.</p></li>

<li><p><span data-x="list append">Append</span> <var>childClone</var> to
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
<var>SelectedContent</var> before null.</p></li>
<var>selectedcontent</var> before null.</p></li>

<var>nodes</var>.</p></li>
</ol>
</li>

<li><p>Let <var>convertedNode</var> be the result of <span>convert nodes into a node</span> given
<var>nodes</var> and <var>option</var>'s <span>node document</span>.</p></li>

<li><p><span>Ensure pre-insertion validity</span> of <var>convertedNode</var> into
<var>SelectedContent</var> before null.</p></li>

<li><p><span data-x="concept-node-replace-all">Replace all</span> with <var>convertedNode</var>
within <var>selectedcontent</var>.</p></li>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
order</span></p></li>
order</span>.</p></li>

</ol>

<p>To <dfn>clear a selectedcontent</dfn> given a <code>selectedcontent</code> element
<var>selectedcontent</var>:</p>

<ol>
<li><p><span data-x="concept-node-remove-ext">Remove</span> all <span
data-x="concept-tree-child">children</span> of <var>selectedcontent</var>, in <span>tree
order</span></p></li>
</ol>

<p>The <code>selectedcontent</code> <span>HTML element insertion steps</span>, given
<var>selectedcontent</var>, are:</p>

<ol>
<li><p>Let <var>nearestSelectAncestor</var> be null.</p></li>

<li><p>Let <var>ancestor</var> be <var>selectedcontent</var>'s <span>parent</span>.</p></li>

<li>
<p><span>While</span> <var>nearestSelectAncestor</var> is null and <var>ancestor</var> is not
null:</p>

<ol>
<li><p>If <var>ancestor</var> is a <code>select</code> element, then set
<var>nearestSelectAncestor</var> to <var>ancestor</var>.</p></li>

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess this is related to Anne's question above, but do we support multiple selectedcontent elements or no?

<li><p>Set <var>ancestor</var> to <var>ancestor</var>'s <span>parent</span>.</p></li>
</ol>
</li>

<li><p>If <var>nearestSelectAncestor</var> is null, then return.</p></li>

<li><p><span data-x="list append">Append</span> <var>selectedcontent</var> to
<var>nearestSelectAncestor</var>'s <span>descendant <code>selectedcontent</code>
elements</span>.</p></li>

<li><p>Let <var>option</var> be the first <code>option</code> in
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, this scares me a bit! You're calling the "clone an option" algorithm from inside the selectedcontent's insertion steps, but these steps must not run script, yet the "clone an option" algorithm can run script, IIUC, because of the "replace all" call.

Given that, I'm actually thinking we should run all of these steps not inside the selected content insertion steps, but maybe its post-connection steps instead — those can run script. A test for this would be great, to confirm my suspicion. It might require some tricks to clone a script that will run during the "clone an option" algorithm.

<var>nearestSelectAncestor</var>'s <span data-x="concept-select-option-list">list of
options</span> whose <span data-x="concept-option-selectedness">selectedness</span> is true, if
any such <code>option</code> exists, otherwise null.</p></li>

<li><p>If <var>option</var> is null, then run <span>clear a selectedcontent</span> given
<var>insertedNode</var>.</p></li>

<li><p>Otherwise, run <span>clone an option into a selectedcontent</span> given <var>option</var>
and <var>insertedNode</var>.</p></li>
</ol>

<p>The <code>selectedcontent</code> <span>HTML element removing steps</span>, given
<var>selectedcontent</var> and <var>oldParent</var>, are:</p>

<ol>
<li>
<p>For each <var>ancestor</var> of <var>selectedcontent</var>'s <span
data-x="ancestor">ancestors</span>:</p>

<ol>
<li><p>If <var>ancestor</var> is a <code>select</code> element, then return.</p></li>
</ol>
</li>

<li>
<p>For each <var>ancestor</var> of <var>oldParent</var>'s <span data-x="inclusive
ancestor">inclusive ancestors</span>:</p>

<ol>
<li>
<p>If <var>ancestor</var> is a <code>select</code> element, then:</p>

<ol>
<li><p><span data-x="list remove">remove</span> <var>selectedcontent</var> from
<var>ancestor</var>'s <span>descendant <code>selectedcontent</code> elements</span>.</p></li>

<li><p>Run <span>clear a selectedcontent</span> given <var>selectedcontent</var>.</p></li>

<li><p>Return.</p></li>
</ol>
</li>
</ol>
</li>
</ol>



<h4 split-filename="form-control-infrastructure">Form control infrastructure</h4>
Expand Down Expand Up @@ -131423,9 +131635,18 @@ document.body.appendChild(text);

<dt>An end tag whose tag name is "option"</dt>
<dd>
<p>If the <span>current node</span> is an <code>option</code> element, then pop that node from
the <span>stack of open elements</span>. Otherwise, this is a <span>parse error</span>; ignore
the token.</p>
<p>If the <span>current node</span> is an <code>option</code> element, then:</p>

<ol>
<li><p>Let <var>option</var> be the <span>current node</span>.</p></li>

<li><p>Pop <var>option</var> from the <span>stack of open elements</span>.</p></li>

<li><p>Run <span>maybe clone an option into selectedcontent</span> given
<var>option</var>.</p></li>
</ol>

<p>Otherwise, this is a <span>parse error</span>; ignore the token.</p>
</dd>

<dt>An end tag whose tag name is "select"</dt>
Expand Down Expand Up @@ -140487,6 +140708,16 @@ interface <dfn interface>External</dfn> {
<td><code>HTMLSelectElement</code></td>
</tr>

<tr>
<th><code>selectedcontent</code></th>
<td>Mirrors content from an <code>option</code></td>
<td>none</td>
<td><code>button</code></td>
<td>empty</td>
<td><span data-x="global attributes">globals</span></td>
<td><code>HTMLSelectedContentElement</code></td>
</tr>

<tr>
<th><code>slot</code></th>
<td>Shadow tree slot</td>
Expand Down Expand Up @@ -143279,6 +143510,10 @@ interface <dfn interface>External</dfn> {
<td> <code>select</code>
<td> <code>HTMLSelectElement</code> : <code>HTMLElement</code>

<tr>
<td> <code>selectedcontent</code>
<td> <code>HTMLSelectedContentElement</code> : <code>HTMLElement</code>

<tr>
<td> <code>slot</code>
<td> <code>HTMLSlotElement</code> : <code>HTMLElement</code>
Expand Down