Skip to content

Commit

Permalink
[css-shadow-parts][css-pseudo] Move various ::part() details to 'part…
Browse files Browse the repository at this point in the history
…-like pseudo-elements'. #10083
  • Loading branch information
tabatkins committed Sep 5, 2024
1 parent 376440d commit 9bb9de1
Show file tree
Hide file tree
Showing 2 changed files with 134 additions and 35 deletions.
54 changes: 37 additions & 17 deletions css-pseudo-4/Overview.bs
Original file line number Diff line number Diff line change
Expand Up @@ -1305,27 +1305,47 @@ Tree-Abiding and Part-Like Pseudo-elements</h2>
parsing/tree-abiding-pseudo-elements.html
</wpt>

<h3 id=partlike>
Part-Like Pseudo-Elements</h3>

A subset of [=tree-abiding pseudo-elements=],
the <dfn>part-like pseudo-elements</dfn>,
the <dfn export lt="part-like|part-like pseudo-element">part-like pseudo-elements</dfn>,
have slightly stronger requirements:
they act as if they have a well-defined location in the document tree.
This enables them to interact with some other platform features
as if they were real elements.

<div class=example>
For example, a [=part-like pseudo-element=]
can be used in the <{html-global/exportparts}> attribute,
to masquerade as a ''::part()''
for the component it's in:

<xmp class=html>
<template id=custom-element-template>
<p exportparts="::before : preceding-text">
You can style my ::before pseudo-element
by using ::part(preceding-text), too!
</template>
</xmp>
</div>
as if they were real elements
(and, in fact, they often <em>are</em> real elements,
such as in the case of ''::part()'',
which simply aren't accessible in the current tree).

[=Part-like pseudo-elements=] inherit from their [=originating element=] by default,
like a standard [=tree-abiding pseudo-element=],
but can declare that they inherit from another element instead
(possibly not accessible).
(For example, ''::part()'' inherits from
the parent of the element it represents in the shadow tree.)

All pseudo-classes and pseudo-elements
are syntactically allowed after a [=part-like pseudo-element=],
such as ''x-button::part(label):hover''
or ''x-button::part(label)::before'',
but some are disallowed from matching:

* The [=structural pseudo-classes=],
'':has()'' pseudo-class,
'':scope'' pseudo-class,
and '':host''/'':host()''/'':host-context()'' pseudo-classes
never match.
* ''::part()'' never matches. (Other [=part-like pseudo-elements=] can, however.)

A [=part-like pseudo-element=] can define itself as representing a real element
(possibly not accessible in the current tree).
If it does so, all pseudo-classes and pseudo-elements match according to that element,
if not disallowed by the previous restrictions.
If it does not do so,
it must define which pseudo-classes it matches and when
(besides the pseudo-classes defined to work on all pseudo-elements,
or all [=tree-abiding pseudo-elements=]).

Unless otherwise specified,
any CSS property that applies to elements
Expand Down
115 changes: 97 additions & 18 deletions css-shadow-parts-1/Overview.bs
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,16 @@ from the sub-parts that it merely happens to contain,
it also helps with encapsulation,
as authors can use ''::part()'' without fear of accidental over-styling.


<!-- Big Text: parts

████▌ ███▌ ████▌ █████▌ ███▌
█▌ █▌ ▐█ ▐█ █▌ █▌ █▌ █▌ █▌
█▌ █▌ █▌ █▌ █▌ █▌ █▌ █▌
████▌ █▌ █▌ ████▌ █▌ ███▌
█▌ █████▌ █▌▐█ █▌ █▌
█▌ █▌ █▌ █▌ ▐█ █▌ █▌ █▌
█▌ █▌ █▌ █▌ █▌ █▌ ███▌
-->
Exposing a Shadow Element: {#exposing}
=============================================================
Elements in a <a>shadow tree</a> may be exported for styling by stylesheets outside the tree
Expand Down Expand Up @@ -146,12 +155,25 @@ and changes to the [=part name lists=] and [=forwarded part name lists=] of elem
then let |innerRoot| be its shadow root.
3. [=calculate the part element map|Calculate=] |innerRoot|'s [=part element map=].
4. For each |innerName|/|outerName| in |el|'s [=forwarded part name list=]:
1. Let |innerParts| be |innerRoot|'s [=part element map=][|innerName|]
2. [=list/Append=] the elements in |innerParts|
to |outerRoot|'s [=part element map=][|outerName|]
1. If |innerName| is an ident:
1. Let |innerParts| be |innerRoot|'s [=part element map=][|innerName|]
2. [=list/Append=] the elements in |innerParts|
to |outerRoot|'s [=part element map=][|outerName|]
2. If |innerName| is a pseudo-element name:
1. [=list/Append=] |innerRoot|'s pseudo-element(s) with that name
to |outerRoot|'s [=part element map=][|outerName|].
</div>

<!-- Big Text: part=""

████▌ ███▌ ████▌ █████▌ ▐█▌ ▐█▌ ▐█▌ ▐█▌
█▌ █▌ ▐█ ▐█ █▌ █▌ █▌ ▐█▌ ▐█▌ ▐█▌ ▐█▌
█▌ █▌ █▌ █▌ █▌ █▌ █▌ ████ █ █ █ █
████▌ █▌ █▌ ████▌ █▌
█▌ █████▌ █▌▐█ █▌ ████
█▌ █▌ █▌ █▌ ▐█ █▌
█▌ █▌ █▌ █▌ █▌ █▌
-->
Naming a Shadow Element: the <{html-global/part}> attribute {#part-attr}
------------------------------------------------------------------------

Expand Down Expand Up @@ -179,6 +201,16 @@ not an id or tagname.
&lt;/script>
</pre>

<!-- Big Text: exportparts

█████▌ █ █ ████▌ ███▌ ████▌ █████▌ ████▌ ███▌ ████▌ █████▌ ███▌
█▌ █ █ █▌ █▌ █▌ █▌ █▌ █▌ █▌ █▌ █▌ ▐█ ▐█ █▌ █▌ █▌ █▌ █▌
█▌ █ █ █▌ █▌ █▌ █▌ █▌ █▌ █▌ █▌ █▌ █▌ █▌ █▌ █▌ █▌ █▌
████ █ ████▌ █▌ █▌ ████▌ █▌ ████▌ █▌ █▌ ████▌ █▌ ███▌
█▌ █ █ █▌ █▌ █▌ █▌▐█ █▌ █▌ █████▌ █▌▐█ █▌ █▌
█▌ █ █ █▌ █▌ █▌ █▌ ▐█ █▌ █▌ █▌ █▌ █▌ ▐█ █▌ █▌ █▌
█████▌ █ █ █▌ ███▌ █▌ █▌ █▌ █▌ █▌ █▌ █▌ █▌ █▌ ███▌
-->
Forwarding a Shadow Element: the <{html-global/exportparts}> attribute {#exportparts-attr}
----------------------------------------------------------------------------------
Any element in a shadow tree can have a <dfn element-attr for=html-global>exportparts</dfn> attribute.
Expand All @@ -200,6 +232,12 @@ Each part mapping is one of:

Note: This is shorthand for <code>ident : ident</code>.

: <code>::ident : outerIdent</code>
:: If <code>::ident</code> is the name of a [=part-like pseudo-element=],
adds <code>::ident</code>/<code>outerIdent</code>
to el's [=forward part name list=].
Otherwise, does nothing.

: anything else
:: Ignored for error-recovery / future compatibility.
</dl>
Expand Down Expand Up @@ -235,8 +273,40 @@ Note: It's okay to map a sub-part to several names.
&lt;/script>
</pre>

<div class=example>
For example, a [=part-like pseudo-element=]
can be used in the <{html-global/exportparts}> attribute,
to masquerade as a ''::part()''
for the component it's in:

<xmp class=html>
<template id=custom-element-template>
<p exportparts="::before : preceding-text, ::after : following-text">
Main text.
</template>
</xmp>

An element using that template
can use a selector like ''x-component::part(preceding-text)''
to target the ''p::before'' pseudo-element in its shadow,
so users of the component don't need to know
that the preceding text is implemented as a pseudo-element.
</div>


<!-- Big Text: ::part()

█▌ █▌ ████▌ ███▌ ████▌ █████▌ ██ ██
███▌ ███▌ █▌ █▌ ▐█ ▐█ █▌ █▌ █▌ █▌ ▐█
█▌ █▌ █▌ █▌ █▌ █▌ █▌ █▌ █▌ █▌ ▐█
████▌ █▌ █▌ ████▌ █▌ █▌ ▐█
█▌ █▌ █▌ █████▌ █▌▐█ █▌ █▌ ▐█
███▌ ███▌ █▌ █▌ █▌ █▌ ▐█ █▌ █▌ ▐█
█▌ █▌ █▌ █▌ █▌ █▌ █▌ █▌ ██ ██
-->

Selecting a Shadow Element: the ''::part()'' pseudo-element {#part}
============================================================================================
===================================================================

The <dfn selector>::part()</dfn> pseudo-element
allows you to select elements that have been exposed via a <{html-global/part}> attribute.
Expand All @@ -248,18 +318,14 @@ The syntax is:

The ''::part()'' pseudo-element only matches anything
when the <a>originating element</a> is a <a>shadow host</a>.
If the <a>originating element's</a> <a>shadow root's</a> <a>part element map</a>
[=map/contains=] all of the specified <<ident>>s,
''::part()'' matches the element or elements keyed to that <<ident>>.
Otherwise, it matches nothing.

<div class="example">
For example,
if you have a custom button
that contains a "label" element that is exposed for styling
(via <code>part="label"</code>),
you can select it with
''#the-button::part(label)''.
''x-button::part(label)''.
</div>

<div class="example">
Expand All @@ -277,15 +343,16 @@ Otherwise, it matches nothing.
(or ''::part(active tab)'', as order doesn't matter).
</div>

The ''::part()'' pseudo-element can take additional pseudo-classes after it,
such as ''x-button::part(label):hover'',
but never matches the <a>structural pseudo-classes</a>
or any other pseudo-classes that match based on tree information
rather than local element information.
The ''::part()'' pseudo-element is a [=part-like pseudo-element=].
If the <a>originating element's</a> <a>shadow root's</a> <a>part element map</a>
[=map/contains=] the specified <<ident>>,
''::part()'' represents the elements keyed to that ident;
if multiple idents are provided and the [=part element map=] contains them all,
it represents the intersection of the elements keyed to each ident.
Otherwise, it matches nothing.

The ''::part()'' pseudo-element can also take additional pseudo-elements after it,
such as ''x-button::part(label)::before'',
but never match additional ''::part()''s.
''::part()'' pseudo-elements inherit according to their position
in the [=originating element's=] shadow tree.

<div class=example>
For example,
Expand All @@ -303,6 +370,18 @@ but never match additional ''::part()''s.
ignoring any other labels.
</div>


<!-- Big Text: CSSOM

███▌ ███▌ ███▌ ███▌ █ █
█▌ █▌ █▌ █▌ █▌ █▌ █▌ █▌ ██ ██
█▌ █▌ █▌ █▌ █▌ █▌█ █▐█
█▌ ███▌ ███▌ █▌ █▌ █▌ █ ▐█
█▌ █▌ █▌ █▌ █▌ █▌ ▐█
█▌ █▌ █▌ █▌ █▌ █▌ █▌ █▌ █▌ ▐█
███▌ ███▌ ███▌ ███▌ █▌ ▐█
-->

Extensions to the {{Element}} Interface {#idl}
==============================================

Expand Down

0 comments on commit 9bb9de1

Please sign in to comment.