@@ -14,14 +14,14 @@ Abstract: This specification defines the ''::part()'' pseudo-element on <a>shado
14
14
15
15
<pre class=link-defaults>
16
16
spec:selectors-4;
17
- type:selector; text::hover
18
- type:dfn; text:live profile
19
- type:dfn; text:structural pseudo-class
17
+ type:selector; text::hover
18
+ type:dfn; text:live profile
19
+ type:dfn; text:structural pseudo-class
20
20
spec:dom; type:dfn; for:/; text:shadow root
21
21
spec:infra;
22
- type:dfn;
23
- text:string
24
- text:list
22
+ type:dfn;
23
+ text:string
24
+ text:list
25
25
</pre>
26
26
27
27
Introduction {#intro}
@@ -66,7 +66,7 @@ it exposed too much of a component's internal structure to scrutiny,
66
66
defeating some of the encapsulation benefits that using Shadow DOM brings.
67
67
For this,
68
68
and other performance-related reasons,
69
- the >>> combinator was eventually removed from the <a>live profile</a> .
69
+ the >>> combinator was eventually dropped .
70
70
71
71
This left us with using <a>custom properties</a> as the only way to style into a shadow tree:
72
72
the component would advertise that it uses certain <a>custom properties</a> to style its internals,
@@ -128,7 +128,7 @@ Each element has a <dfn export for="element">part name list</dfn>
128
128
which is an [=ordered set=] of tokens.
129
129
130
130
Each element has a <dfn export for="element">forwarded part name list</dfn>
131
- which is a [=list=] of [=pairs =]
131
+ which is a [=list=] of [=tuples =]
132
132
containing a [=string=] for the inner part being forwarded
133
133
and a [=string=] giving the name it will be exposed as.
134
134
@@ -155,13 +155,13 @@ and changes to the [=part name lists=] and [=forwarded part name lists=] of elem
155
155
then let |innerRoot| be its shadow root.
156
156
3. [=calculate the part element map|Calculate=] |innerRoot|'s [=part element map=] .
157
157
4. For each |innerName|/|outerName| in |el|'s [=forwarded part name list=] :
158
- 1. If |innerName| is an ident:
159
- 1. Let |innerParts| be |innerRoot|'s [=part element map=] [|innerName|]
160
- 2. [=list/Append=] the elements in |innerParts|
161
- to |outerRoot|'s [=part element map=] [|outerName|]
162
- 2. If |innerName| is a pseudo-element name:
163
- 1. [=list/Append=] |innerRoot|'s pseudo-element(s) with that name
164
- to |outerRoot|'s [=part element map=] [|outerName|] .
158
+ 1. If |innerName| is an ident:
159
+ 1. Let |innerParts| be |innerRoot|'s [=part element map=] [|innerName|]
160
+ 2. [=list/Append=] the elements in |innerParts|
161
+ to |outerRoot|'s [=part element map=] [|outerName|]
162
+ 2. If |innerName| is a pseudo-element name:
163
+ 1. [=list/Append=] |innerRoot|'s pseudo-element(s) with that name
164
+ to |outerRoot|'s [=part element map=] [|outerName|] .
165
165
</div>
166
166
167
167
<!-- Big Text: part=""
@@ -188,16 +188,16 @@ not an id or tagname.
188
188
189
189
<pre class="example">
190
190
<style>
191
- c-e<b> ::part(textspan)</b> { color: red; }
191
+ c-e<b> ::part(textspan)</b> { color: red; }
192
192
</style>
193
193
194
194
<template id="c-e-template">
195
- <span <b> part="textspan"</b> >This text will be red</span>
195
+ <span <b> part="textspan"</b> >This text will be red</span>
196
196
</template>
197
197
<c-e></c-e>
198
198
<script>
199
- // Add template as custom element c-e
200
- ...
199
+ // Add template as custom element c-e
200
+ ...
201
201
</script>
202
202
</pre>
203
203
@@ -224,73 +224,73 @@ The exportparts attribute is parsed as a comma-separated list of part mappings.
224
224
Each part mapping is one of:
225
225
226
226
<dl class=switch>
227
- : <code> innerIdent : outerIdent</code>
228
- :: Adds <code> innerIdent</code> /<code> outerIdent</code> to el's <a>forwarded part name list</a> .
227
+ : <code> innerIdent : outerIdent</code>
228
+ :: Adds <code> innerIdent</code> /<code> outerIdent</code> to el's <a>forwarded part name list</a> .
229
229
230
- : <code> ident</code>
231
- :: Adds <code> ident</code> /<code> ident</code> to el's <a>forwarded part name list</a> .
230
+ : <code> ident</code>
231
+ :: Adds <code> ident</code> /<code> ident</code> to el's <a>forwarded part name list</a> .
232
232
233
233
Note: This is shorthand for <code> ident : ident</code> .
234
234
235
- : <code> ::ident : outerIdent</code>
236
- :: If <code> ::ident</code> is the name of a [=part-like pseudo-element=] ,
237
- adds <code> ::ident</code> /<code> outerIdent</code>
238
- to el's [=forward part name list=] .
239
- Otherwise, does nothing.
235
+ : <code> ::ident : outerIdent</code>
236
+ :: If <code> ::ident</code> is the name of a [=fully styleable pseudo-element=] ,
237
+ adds <code> ::ident</code> /<code> outerIdent</code>
238
+ to el's [=forward part name list=] .
239
+ Otherwise, does nothing.
240
240
241
- : anything else
242
- :: Ignored for error-recovery / future compatibility.
241
+ : anything else
242
+ :: Ignored for error-recovery / future compatibility.
243
243
</dl>
244
244
245
245
Note: It's okay to map a sub-part to several names.
246
246
247
247
<pre class="example">
248
248
<style>
249
- c-e<b> ::part(textspan)</b> { color: red; }
249
+ c-e<b> ::part(textspan)</b> { color: red; }
250
250
</style>
251
251
252
252
<template id="c-e-outer-template">
253
- <c-e-inner <b> exportparts="innerspan: textspan"</b> ></c-e-inner>
253
+ <c-e-inner <b> exportparts="innerspan: textspan"</b> ></c-e-inner>
254
254
</template>
255
255
256
256
<template id="c-e-inner-template">
257
- <span <b> part="innerspan"</b> >
258
- This text will be red because the containing shadow
259
- host forwards <b> innerspan</b> to the document as "textspan"
260
- and the document style matches it.
261
- </span>
262
- <span <b> part="textspan"</b> >
263
- This text will not be red because <b> textspan</b> in the document style
264
- cannot match against the part inside the inner custom element
265
- if it is not forwarded.
257
+ <span <b> part="innerspan"</b> >
258
+ This text will be red because the containing shadow
259
+ host forwards <b> innerspan</b> to the document as "textspan"
260
+ and the document style matches it.
261
+ </span>
262
+ <span <b> part="textspan"</b> >
263
+ This text will not be red because <b> textspan</b> in the document style
264
+ cannot match against the part inside the inner custom element
265
+ if it is not forwarded.
266
266
</span>
267
267
</template>
268
268
269
269
<c-e></c-e>
270
270
<script>
271
- // Add template as custom elements c-e-inner, c-e-outer
272
- ...
271
+ // Add template as custom elements c-e-inner, c-e-outer
272
+ ...
273
273
</script>
274
274
</pre>
275
275
276
276
<div class=example>
277
- For example, a [=part-like pseudo-element=]
278
- can be used in the <{html-global/exportparts}> attribute,
279
- to masquerade as a ''::part()''
280
- for the component it's in:
281
-
282
- <xmp class=html>
283
- <template id=custom-element-template>
284
- <p exportparts="::before : preceding-text, ::after : following-text">
285
- Main text.
286
- </template>
287
- </xmp>
288
-
289
- An element using that template
290
- can use a selector like ''x-component::part(preceding-text)''
291
- to target the ''p::before'' pseudo-element in its shadow,
292
- so users of the component don't need to know
293
- that the preceding text is implemented as a pseudo-element.
277
+ For example, a [=fully styleable pseudo-element=]
278
+ can be used in the <{html-global/exportparts}> attribute,
279
+ to masquerade as a ''::part()''
280
+ for the component it's in:
281
+
282
+ <xmp class=html>
283
+ <template id=custom-element-template>
284
+ <p exportparts="::before : preceding-text, ::after : following-text">
285
+ Main text.
286
+ </template>
287
+ </xmp>
288
+
289
+ An element using that template
290
+ can use a selector like ''x-component::part(preceding-text)''
291
+ to target the ''p::before'' pseudo-element in its shadow,
292
+ so users of the component don't need to know
293
+ that the preceding text is implemented as a pseudo-element.
294
294
</div>
295
295
296
296
@@ -299,7 +299,7 @@ Note: It's okay to map a sub-part to several names.
299
299
█▌ █▌ ████▌ ███▌ ████▌ █████▌ ██ ██
300
300
███▌ ███▌ █▌ █▌ ▐█ ▐█ █▌ █▌ █▌ █▌ ▐█
301
301
█▌ █▌ █▌ █▌ █▌ █▌ █▌ █▌ █▌ █▌ ▐█
302
- ████▌ █▌ █▌ ████▌ █▌ █▌ ▐█
302
+ ████▌ █▌ █▌ ████▌ █▌ █▌ ▐█
303
303
█▌ █▌ █▌ █████▌ █▌▐█ █▌ █▌ ▐█
304
304
███▌ ███▌ █▌ █▌ █▌ █▌ ▐█ █▌ █▌ ▐█
305
305
█▌ █▌ █▌ █▌ █▌ █▌ █▌ █▌ ██ ██
@@ -313,19 +313,19 @@ allows you to select elements that have been exposed via a <{html-global/part}>
313
313
The syntax is:
314
314
315
315
<pre class=prod>
316
- ::part() = ::part( <<ident>> + )
316
+ ::part() = ::part( <<ident>> + )
317
317
</pre>
318
318
319
319
The ''::part()'' pseudo-element only matches anything
320
320
when the <a>originating element</a> is a <a>shadow host</a> .
321
321
322
322
<div class="example">
323
- For example,
324
- if you have a custom button
325
- that contains a "label" element that is exposed for styling
326
- (via <code> part="label"</code> ),
327
- you can select it with
328
- ''x-button::part(label)'' .
323
+ For example,
324
+ if you have a custom button
325
+ that contains a "label" element that is exposed for styling
326
+ (via <code> part="label"</code> ),
327
+ you can select it with
328
+ ''x-button::part(label)'' .
329
329
</div>
330
330
331
331
<div class="example">
@@ -343,7 +343,7 @@ when the <a>originating element</a> is a <a>shadow host</a>.
343
343
(or ''::part(active tab)'' , as order doesn't matter).
344
344
</div>
345
345
346
- The ''::part()'' pseudo-element is a [=part-like pseudo-element=] .
346
+ The ''::part()'' pseudo-element is a [=fully styleable pseudo-element=] .
347
347
If the <a>originating element's</a> <a>shadow root's</a> <a>part element map</a>
348
348
[=map/contains=] the specified <<ident>> ,
349
349
''::part()'' represents the elements keyed to that ident;
@@ -355,19 +355,19 @@ Otherwise, it matches nothing.
355
355
in the [=originating element's=] shadow tree.
356
356
357
357
<div class=example>
358
- For example,
359
- ''x-panel::part(confirm-button)::part(label)''
360
- never matches anything.
361
- This is because doing so would expose more structural information
362
- than is intended.
363
-
364
- If the <code> <x-panel></code> 's internal confirm button had used something like
365
- <code> part="label => confirm-label"</code>
366
- to forward the button's internal parts up into the panel's own <a>part element map</a> ,
367
- then a selector like
368
- ''x-panel::part(confirm-label)''
369
- would select just the one button's label,
370
- ignoring any other labels.
358
+ For example,
359
+ ''x-panel::part(confirm-button)::part(label)''
360
+ never matches anything.
361
+ This is because doing so would expose more structural information
362
+ than is intended.
363
+
364
+ If the <code> <x-panel></code> 's internal confirm button had used something like
365
+ <code> part="label => confirm-label"</code>
366
+ to forward the button's internal parts up into the panel's own <a>part element map</a> ,
367
+ then a selector like
368
+ ''x-panel::part(confirm-label)''
369
+ would select just the one button's label,
370
+ ignoring any other labels.
371
371
</div>
372
372
373
373
@@ -387,7 +387,7 @@ Extensions to the {{Element}} Interface {#idl}
387
387
388
388
<pre class=idl>
389
389
partial interface Element {
390
- [SameObject, PutForwards=value] readonly attribute DOMTokenList part;
390
+ [SameObject, PutForwards=value] readonly attribute DOMTokenList part;
391
391
};
392
392
</pre>
393
393
@@ -404,7 +404,7 @@ Microsyntaxes for parsing {#parsing}
404
404
Rules for parsing part mappings {#parsing-mapping}
405
405
----------------------------------------------
406
406
407
- A <dfn export>valid part mapping</dfn> is a [=pair =] of tokens
407
+ A <dfn export>valid part mapping</dfn> is a [=tuple =] of tokens
408
408
separated by a U+003A COLON character
409
409
and any number of space characters before or after the U+003A COLON
410
410
The tokens must not contain U+003A COLON or U+002C COMMA characters.
@@ -417,19 +417,19 @@ The rules for parsing a part mapping are as follows:
417
417
418
418
1. [=Collect a sequence of code points=] that are space characters
419
419
1. [=Collect a sequence of code points=] that are not space characters or U+003A COLON characters,
420
- and let <var> first token</var> be the result.
420
+ and let <var> first token</var> be the result.
421
421
1. If <var> first token</var> is empty then return error.
422
422
1. [=Collect a sequence of code points=] that are space characters.
423
- 1. If the end of the <var> input</var> has been reached, return the [=pair =] <var> first token</var> / <var> first token</var>
423
+ 1. If the end of the <var> input</var> has been reached, return the [=tuple =] ( <var> first token</var> , <var> first token</var> )
424
424
1. If character at <var> position</var> is not a U+003A COLON character, return error.
425
425
1. Consume the U+003A COLON character.
426
426
1. [=Collect a sequence of code points=] that are space characters.
427
427
1. [=Collect a sequence of code points=] that are not space characters or U+003A COLON characters.
428
- and let <var> second token</var> be the result.
428
+ and let <var> second token</var> be the result.
429
429
1. If <var> second token</var> is empty then return error.
430
430
1. [=Collect a sequence of code points=] that are space characters.
431
431
1. If <var> position</var> is not past the end of <var> input</var> then return error.
432
- 1. Return the [=pair =] <var> first token</var> / <var> second token</var> .
432
+ 1. Return the [=tuple =] ( <var> first token</var> , <var> second token</var> ) .
433
433
434
434
Rules for parsing a list of part mappings {#parsing-mapping-list}
435
435
----------------------------------------------
@@ -443,18 +443,32 @@ The rules for parsing a list of part mappings are as follow:
443
443
1. Let <var> input</var> be the string being parsed.
444
444
445
445
1. [=split a string on commas|Split the string <var>input</var> on commas=] .
446
- Let <var> unparsed mappings</var> be the resulting list of strings.
446
+ Let <var> unparsed mappings</var> be the resulting list of strings.
447
447
448
- 1. Let <var> mappings</var> be an initially empty [=list=] of [=pairs =] of tokens.
449
- This [=list=] will be the result of this algorithm.
448
+ 1. Let <var> mappings</var> be an initially empty [=list=] of [=tuples =] of tokens.
449
+ This [=list=] will be the result of this algorithm.
450
450
451
451
1. For each string <var> unparsed mapping</var> in <var> unparsed mappings</var> ,
452
- run the following substeps:
453
-
454
- 1. If <var> unparsed mapping</var> is empty or contains only space characters,
455
- continue to the next iteration of the loop.
456
- 1. Let <var> mapping</var> be the result of parsing <var> unparsed mapping</var>
457
- using the <span> rules for parsing part mappings</span> .
458
- 1. If <var> mapping</var> is an error then continue to the next iteration of the loop.
459
- This allows clients to skip over new syntax that is not understood.
460
- 1. Append <var> mapping</var> to <var> mappings</var> .
452
+ run the following substeps:
453
+
454
+ 1. If <var> unparsed mapping</var> is empty or contains only space characters,
455
+ continue to the next iteration of the loop.
456
+ 1. Let <var> mapping</var> be the result of parsing <var> unparsed mapping</var>
457
+ using the <span> rules for parsing part mappings</span> .
458
+ 1. If <var> mapping</var> is an error then continue to the next iteration of the loop.
459
+ This allows clients to skip over new syntax that is not understood.
460
+ 1. Append <var> mapping</var> to <var> mappings</var> .
461
+
462
+ <h2 id=priv>
463
+ Privacy Considerations</h2>
464
+
465
+ This specification defines new ways to target styling of elements on the page,
466
+ which are already fully styleable in other ways.
467
+ As such, it introduces no new privacy considerations.
468
+
469
+ <h2 id=sec>
470
+ Security Considerations</h2>
471
+
472
+ As [=shadow trees=] are intentionally not a security boundary,
473
+ merely a convenience for page authors,
474
+ exposing them to selectors in this way introduces no new security considerations.
0 commit comments