@@ -14,14 +14,14 @@ Abstract: This specification defines the ''::part()'' pseudo-element on <a>shado
1414
1515<pre class=link-defaults>
1616spec: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
2020spec:dom; type:dfn; for:/; text:shadow root
2121spec:infra;
22- type:dfn;
23- text:string
24- text:list
22+ type:dfn;
23+ text:string
24+ text:list
2525</pre>
2626
2727Introduction {#intro}
@@ -66,7 +66,7 @@ it exposed too much of a component's internal structure to scrutiny,
6666defeating some of the encapsulation benefits that using Shadow DOM brings.
6767For this,
6868and other performance-related reasons,
69- the >>> combinator was eventually removed from the <a>live profile</a> .
69+ the >>> combinator was eventually dropped .
7070
7171This left us with using <a>custom properties</a> as the only way to style into a shadow tree:
7272the 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>
128128which is an [=ordered set=] of tokens.
129129
130130Each 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 =]
132132containing a [=string=] for the inner part being forwarded
133133and a [=string=] giving the name it will be exposed as.
134134
@@ -155,13 +155,13 @@ and changes to the [=part name lists=] and [=forwarded part name lists=] of elem
155155 then let |innerRoot| be its shadow root.
156156 3. [=calculate the part element map|Calculate=] |innerRoot|'s [=part element map=] .
157157 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|] .
165165</div>
166166
167167<!-- Big Text: part=""
@@ -188,16 +188,16 @@ not an id or tagname.
188188
189189<pre class="example">
190190<style>
191- c-e<b> ::part(textspan)</b> { color: red; }
191+ c-e<b> ::part(textspan)</b> { color: red; }
192192</style>
193193
194194<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>
196196</template>
197197<c-e></c-e>
198198<script>
199- // Add template as custom element c-e
200- ...
199+ // Add template as custom element c-e
200+ ...
201201</script>
202202</pre>
203203
@@ -224,73 +224,73 @@ The exportparts attribute is parsed as a comma-separated list of part mappings.
224224Each part mapping is one of:
225225
226226<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> .
229229
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> .
232232
233233 Note: This is shorthand for <code> ident : ident</code> .
234234
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.
240240
241- : anything else
242- :: Ignored for error-recovery / future compatibility.
241+ : anything else
242+ :: Ignored for error-recovery / future compatibility.
243243</dl>
244244
245245Note: It's okay to map a sub-part to several names.
246246
247247<pre class="example">
248248<style>
249- c-e<b> ::part(textspan)</b> { color: red; }
249+ c-e<b> ::part(textspan)</b> { color: red; }
250250</style>
251251
252252<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>
254254</template>
255255
256256<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.
266266 </span>
267267</template>
268268
269269<c-e></c-e>
270270<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+ ...
273273</script>
274274</pre>
275275
276276<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.
294294</div>
295295
296296
@@ -299,7 +299,7 @@ Note: It's okay to map a sub-part to several names.
299299 █▌ █▌ ████▌ ███▌ ████▌ █████▌ ██ ██
300300███▌ ███▌ █▌ █▌ ▐█ ▐█ █▌ █▌ █▌ █▌ ▐█
301301 █▌ █▌ █▌ █▌ █▌ █▌ █▌ █▌ █▌ █▌ ▐█
302- ████▌ █▌ █▌ ████▌ █▌ █▌ ▐█
302+ ████▌ █▌ █▌ ████▌ █▌ █▌ ▐█
303303 █▌ █▌ █▌ █████▌ █▌▐█ █▌ █▌ ▐█
304304███▌ ███▌ █▌ █▌ █▌ █▌ ▐█ █▌ █▌ ▐█
305305 █▌ █▌ █▌ █▌ █▌ █▌ █▌ █▌ ██ ██
@@ -313,19 +313,19 @@ allows you to select elements that have been exposed via a <{html-global/part}>
313313The syntax is:
314314
315315<pre class=prod>
316- ::part() = ::part( <<ident>> + )
316+ ::part() = ::part( <<ident>> + )
317317</pre>
318318
319319The ''::part()'' pseudo-element only matches anything
320320when the <a>originating element</a> is a <a>shadow host</a> .
321321
322322<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)'' .
329329</div>
330330
331331<div class="example">
@@ -343,7 +343,7 @@ when the <a>originating element</a> is a <a>shadow host</a>.
343343 (or ''::part(active tab)'' , as order doesn't matter).
344344</div>
345345
346- The ''::part()'' pseudo-element is a [=part-like pseudo-element=] .
346+ The ''::part()'' pseudo-element is a [=fully styleable pseudo-element=] .
347347If the <a>originating element's</a> <a>shadow root's</a> <a>part element map</a>
348348[=map/contains=] the specified <<ident>> ,
349349''::part()'' represents the elements keyed to that ident;
@@ -355,19 +355,19 @@ Otherwise, it matches nothing.
355355in the [=originating element's=] shadow tree.
356356
357357<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.
371371</div>
372372
373373
@@ -387,7 +387,7 @@ Extensions to the {{Element}} Interface {#idl}
387387
388388<pre class=idl>
389389partial interface Element {
390- [SameObject, PutForwards=value] readonly attribute DOMTokenList part;
390+ [SameObject, PutForwards=value] readonly attribute DOMTokenList part;
391391};
392392</pre>
393393
@@ -404,7 +404,7 @@ Microsyntaxes for parsing {#parsing}
404404Rules for parsing part mappings {#parsing-mapping}
405405----------------------------------------------
406406
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
408408separated by a U+003A COLON character
409409and any number of space characters before or after the U+003A COLON
410410The 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:
417417
4184181. [=Collect a sequence of code points=] that are space characters
4194191. [=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.
4214211. If <var> first token</var> is empty then return error.
4224221. [=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> )
4244241. If character at <var> position</var> is not a U+003A COLON character, return error.
4254251. Consume the U+003A COLON character.
4264261. [=Collect a sequence of code points=] that are space characters.
4274271. [=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.
4294291. If <var> second token</var> is empty then return error.
4304301. [=Collect a sequence of code points=] that are space characters.
4314311. 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> ) .
433433
434434Rules for parsing a list of part mappings {#parsing-mapping-list}
435435----------------------------------------------
@@ -443,18 +443,32 @@ The rules for parsing a list of part mappings are as follow:
4434431. Let <var> input</var> be the string being parsed.
444444
4454451. [=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.
447447
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.
450450
4514511. 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