@@ -2761,6 +2761,7 @@ a.setAttribute('href', 'https://example.com/'); // change the content attribute
2761
2761
<li><dfn data-x="LegacyTreatNonObjectAsNull" data-x-href="https://webidl.spec.whatwg.org/#LegacyTreatNonObjectAsNull"><code>[LegacyTreatNonObjectAsNull]</code></dfn></li>
2762
2762
<li><dfn data-x="LegacyUnenumerableNamedProperties" data-x-href="https://webidl.spec.whatwg.org/#LegacyUnenumerableNamedProperties"><code>[LegacyUnenumerableNamedProperties]</code></dfn></li>
2763
2763
<li><dfn data-x="LegacyUnforgeable" data-x-href="https://webidl.spec.whatwg.org/#LegacyUnforgeable"><code>[LegacyUnforgeable]</code></dfn></li>
2764
+ <li><dfn data-x-href="https://webidl.spec.whatwg.org/#es-add-delete">Default add operation</dfn></li>
2764
2765
</ul>
2765
2766
2766
2767
<p><cite>Web IDL</cite> also defines the following types that are used in Web IDL fragments in
@@ -3902,6 +3903,7 @@ a.setAttribute('href', 'https://example.com/'); // change the content attribute
3902
3903
<li>The <dfn data-x-href="https://drafts.csswg.org/css-values/#pt">'pt'</dfn> unit</li>
3903
3904
<li>The <dfn data-x-href="https://drafts.csswg.org/css-values/#funcdef-attr">'attr()'</dfn> function</li>
3904
3905
<li>The <dfn data-x-href="https://drafts.csswg.org/css-values/#math-function">math functions</dfn></li>
3906
+ <li>The <dfn data-x-href="https://drafts.csswg.org/css-values-4/#typedef-dashed-ident">dashed ident</dfn> identifier</li>
3905
3907
</ul>
3906
3908
3907
3909
<p>The term <dfn data-x="css-styling-attribute"
@@ -70681,6 +70683,8 @@ interface <dfn interface>ElementInternals</dfn> {
70681
70683
boolean <span data-x="dom-ElementInternals-reportValidity">reportValidity</span>();
70682
70684
70683
70685
readonly attribute <span>NodeList</span> <span data-x="dom-ElementInternals-labels">labels</span>;
70686
+
70687
+ [SameObject] readonly attribute <span>CustomStateSet</span> <dfn data-x="dom-elementinternals-states">states</dfn>;
70684
70688
};
70685
70689
70686
70690
// <a href="#accessibility-semantics">Accessibility semantics</a>
@@ -71047,6 +71051,153 @@ dictionary <dfn dictionary>ValidityStateFlags</dfn> {
71047
71051
71048
71052
</div>
71049
71053
71054
+ <h4>Custom state pseudo class</h4>
71055
+
71056
+ <!-- my own attempt at an intro/definition -->
71057
+
71058
+ <p>The <dfn>custom state pseudo class</dfn> allows <span data-x="custom element">custom
71059
+ elements</span> to set and remove <span data-x="pseudo-class">pseudo classes</span> with custom
71060
+ names starting with <span data-x="">"--"</span>.</p>
71061
+
71062
+ <!-- the wicg spec's intro/definition. which is better? -->
71063
+
71064
+ <p>The <span>custom state pseudo class</span> allows <span data-x="custom element">custom
71065
+ elements</span> to inform custom element's states to the user agent, and a
71066
+ <span>pseudo-class</span> to select elements with specific states. The former is the <span
71067
+ data-x="dom-elementinternals-states">states</span> IDL attribute of <code>ElementInternals</code>,
71068
+ and the latter is the <span>custom state pseudo class</span>.</p>
71069
+
71070
+ <!-- The next two paragraphs are "motivation" from the wicg spec. should they be included...? -->
71071
+
71072
+ <p>Built-in elements provided by user agents have certain “states” that can change over time
71073
+ depending on user interaction and other factors, and are exposed to web authors through <span
71074
+ data-x="pseudo-class">pseudo classes</span>. For example, some form controls have the "invalid"
71075
+ state, which is exposed through the <code data-x="selector-invalid">:invalid</code>
71076
+ <span>pseudo-class</span>.</p>
71077
+
71078
+ <p>Like built-in elements, <span data-x="custom element">custom elements</span> can have various
71079
+ states to be in too, and <span>custom element</span> authors want to expose these states in a
71080
+ similar fashion as the built-in elements.</p>
71081
+
71082
+ <div class="example">
71083
+ <p>The following shows how a <span>custom state pseudo class</span> can be used to style a custom
71084
+ checkbox element. Assume that <code data-x="">LabeledCheckbox</code> doesn't expose its "checked"
71085
+ state via a content attribute.</p>
71086
+
71087
+ <pre><code class="html"><script>
71088
+ class LabeledCheckbox extends HTMLElement {
71089
+ constructor() {
71090
+ super();
71091
+ this._internals = this.attachInternals();
71092
+ this.addEventListener('click', this._onClick.bind(this));
71093
+
71094
+ const shadowRoot = this.attachShadow({mode: 'closed'});
71095
+ shadowRoot.innerHTML =
71096
+ `<style>
71097
+ :host::before {
71098
+ content: '[ ]';
71099
+ white-space: pre;
71100
+ font-family: monospace;
71101
+ }
71102
+ :host(:--checked)::before { content: '[x]' }
71103
+ </style>
71104
+ <slot>Label</slot>`;
71105
+ }
71106
+
71107
+ get checked() { return this._internals.states.has('--checked'); }
71108
+
71109
+ set checked(flag) {
71110
+ if (flag)
71111
+ this._internals.states.add('--checked');
71112
+ else
71113
+ this._internals.states.delete('--checked');
71114
+ }
71115
+
71116
+ _onClick(event) {
71117
+ this.checked = !this.checked;
71118
+ }
71119
+ }
71120
+
71121
+ customElements.define('labeled-checkbox', LabeledCheckbox);
71122
+ </script>
71123
+
71124
+ <style>
71125
+ labeled-checkbox { border: dashed red; }
71126
+ labeled-checkbox:--checked { border: solid; }
71127
+ </style>
71128
+
71129
+ <labeled-checkbox>You need to check this</labeled-checkbox>
71130
+
71131
+ <!-- Works even on ::part()s -->
71132
+ <script>
71133
+ class QuestionBox extends HTMLElement {
71134
+ constructor() {
71135
+ super();
71136
+ const shadowRoot = this.attachShadow({mode: 'closed'});
71137
+ shadowRoot.innerHTML =
71138
+ `<div><slot>Question</slot></div>
71139
+ <labeled-checkbox part='checkbox'>Yes</labeled-checkbox>`;
71140
+ }
71141
+ }
71142
+ customElements.define('question-box', QuestionBox);
71143
+ </script>
71144
+
71145
+ <style>
71146
+ question-box::part(checkbox) { color: red; }
71147
+ question-box::part(checkbox):--checked { color: green; }
71148
+ </style>
71149
+
71150
+ <question-box>Continue?</question-box></code></pre>
71151
+ </div>
71152
+
71153
+ <!-- TODO should i keep this heading? its in the wicg draft spec -->
71154
+ <h5>Exposing custom element states</h5>
71155
+
71156
+ <p>Each <span>autonomous custom element</span> has a <dfn>states set</dfn>, which is a
71157
+ <code>CustomStateSet</code>, initially empty.</p>
71158
+
71159
+ <span data-x="concept-element-dom">DOM interface</span>:
71160
+ <pre><code class="idl">[Exposed=Window]
71161
+ interface <dfn>CustomStateSet</dfn> {
71162
+ setlike<DOMString>;
71163
+ undefined add(DOMString value);
71164
+ };</code></pre>
71165
+
71166
+ <!-- TODO should this go next to the IDL code of ElementInternals instead? -->
71167
+ <p>The <dfn for="HTMLElement"><code data-x="dom-htmlelement-states">states</code></dfn> IDL
71168
+ attribute must return the <span>states set</span>.</p>
71169
+
71170
+ <p>The <dfn for="CustomStateSet"><code
71171
+ data-x="dom-customstateset-add">add(<var>value</var>)</code></dfn> method must run the following
71172
+ steps:</p>
71173
+
71174
+ <ol>
71175
+ <!-- TODO the draft spec doesn't say what "match" means. Should it be defined? Should I just
71176
+ say "starts with" instead? -->
71177
+ <li><p>If <var>value</var> does not match <span data-x="dashed ident"><dashed-ident></span>,
71178
+ then throw a <span>"<code>SyntaxError</code>"</span> <code>DOMException</code>.</p></li>
71179
+
71180
+ <li><p>Invoke the <span>default add operation</span>, which the <code
71181
+ data-x="">setlike<DOMString></code> would have if <code>CustomStateSet</code> interface had no
71182
+ <code data-x="dom-customstateset-add">add</code> operation, given <var>value</var>.</p></li>
71183
+ </ol>
71184
+
71185
+ <div class="example">
71186
+ <p><span>States set</span> can expose boolean states represented by existence/non-existence of
71187
+ string values. If an author wants to expose a state which can have three values, it can be
71188
+ converted to three exclusive boolean states. For example, a state called <code
71189
+ data-x="">readyState</code> with <code data-x="">"loading"</code>, <code
71190
+ data-x="">"interactive"</code>, and <code data-x="">"complete"</code> values can be mapped to
71191
+ three exclusive boolean states, <code data-x="">"--loading"</code>, <code
71192
+ data-x="">"--interactive"</code>, and <code data-x="">"--complete"</code>.
71193
+
71194
+ <pre><code class="js">// Change the readyState from anything to "complete".
71195
+ this._readyState = "complete";
71196
+ this._internals.states.delete("--loading");
71197
+ this._internals.states.delete("--interactive");
71198
+ this._internals.states.add("--complete");</code></pre>
71199
+ </div>
71200
+
71050
71201
<h3 split-filename="semantics-other" id="common-idioms">Common idioms without dedicated elements</h3>
71051
71202
71052
71203
<h4 id="rel-up">Breadcrumb navigation</h4>
@@ -71976,6 +72127,14 @@ Demos:
71976
72127
elements whose <span data-x="the directionality">directionality</span> is '<span
71977
72128
data-x="concept-rtl">rtl</span>'.</p>
71978
72129
</dd>
72130
+
72131
+ <dt><dfn selector noexport data-x="selector-custom">Custom state pseudo class</dfn></dt>
72132
+ <dd>
72133
+ <p>The <span data-x="selector-custom">custom state pseudo class</span> is any selector which
72134
+ begins with <span data-x="dashed ident"><dashed-ident></span>. It must match any element that
72135
+ is an <span>autonomous custom element</span> and whose <span>states set</span> contains a string
72136
+ matching the name of the pseudo class.</p>
72137
+ </dd>
71979
72138
</dl>
71980
72139
71981
72140
<p class="note">This specification does not define when an element matches the <code undefined
0 commit comments