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

[css-shadow-parts][css-pseudo] Move various ::part() details to 'part-like pseudo-element'. #10839

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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