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-scoping-1] add :has-slotted() pseudo class #10586

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
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
42 changes: 40 additions & 2 deletions css-scoping-1/Overview.bs
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,44 @@ Selecting Slot-Assigned Content: the ''::slotted()'' pseudo-element</h4>
The only way to style assigned text nodes
is by styling the <a>slot</a> and relying on inheritance.

<h4 id='has-slotted-pseudo'>
Matching Selectors Against Slot-Assigned Content: the '':has-slotted()'' pseudo-class</h4>

The <dfn selector>:has-slotted()</dfn> pseudo-class, when evaluated
<a>in the context of a shadow tree</a>,
matches the <a>slot</a>, if one of its
<a lt="find flattened slottables">assigned elements, after flattening,</a> matches the provided <<compound-selector>>.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"after flattening" is interesting here because it give "non-slotted" content while being required to gather all slotted content. E.G.:

<div>
  <template shadowrootmode="open">
    <style>
      div {
        color: green;
      }
      :has-slotted(div) {
        color: red;
      }
    </style>
    <slot><div>Test</div></slot>
  </template>
</div>

In the example above "Test" will display red in the case that flattened elements are leveraged.

However, if you don't use flattened elements:

<div>
  <template shadowrootmode="open">
    <div>
      <template shadowrootmode="open">
        <style>
          div {
            color: green;
          }
          :has-slotted(div) {
            color: red;
          }
        </style>
        <slot></slot>
      </template>
      <slot><div>Test</div></slot>
    </div>
  </template>
</div>

This "Test" will also be red. And, without flattened elements,

<div>
  <template shadowrootmode="open">
    <div>
      <template shadowrootmode="open">
        <style>
          div {
            color: green;
          }
          :has-slotted(div) {
            color: red;
          }
        </style>
        <slot></slot>
      </template>
      <div>Test</div>
    </div>
  </template>
</div>

This "Test" will also be red.

I'm not sure it's a real thing, but is there a place between ::slotted(*) and .assignedElements({flatten: true}) that would resolve the external assigned to a slot and not the default ones internal to the shadow host?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For consistency, I think it's important that :has-slotted matches using the same rules for matchable elements as ::slotted.

Concretely, since ::slotted() never matches either <slot> or fallback content, :has-slotted also should not match when it would by selecting either <slot> or fallback content.

See #5482. IMO, the spec is still very confusing and possibly indicates that this should match, but the CSS working group resolved that the current behavior is intended in #5482.

I think matching against fallback content both for ::slotted and :has-slotted is valuable, but I suggest it should be tackled as a follow-on to this feature.

In any other context, it matches nothing. This pseudo-class only exists on <a>slots</a>.

The [=specificity=] of '':has-slotted()'' is that of a pseudo-class,
plus the [=specificity=] of its argument.

The grammar of the '':has-slotted()'' pseudo-element is:

<pre class=prod>:has-slotted( <<compound-selector>> )</pre>

<div class="example">
For example, say you had a component with both children and a shadow tree,
like the following:

<pre>
&lt;x-foo>
&lt;div id="one" slot="foo" class="foo">...&lt;/div>
&lt;"shadow tree">

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you want to use the <::shadow> markup here?

&lt;slot id="theslot" name="foo">&lt;/slot>
&lt;/"shadow tree">
&lt;/x-foo>
</pre>

For a stylesheet within the <a>shadow tree</a>,
selectors like '':has-slotted(*)'', '':has-slotted(div)'', '':has-slotted(.foo)'', and '':has-slotted(#one)''
will match ''#theslot'', while '':has-slotted(p)'', '':has-slotted(:not(.foo))'', '':has-slotted(#two)''
will not.
</div>

Note: '':has-slotted()'' will only match the ''slot'' element, not the contents. Slotted contents
can be matched with the ''::slotted()'' pseudo-element.

<!--
██████ ███ ██████ ██████ ███ ████████ ████████
██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
Expand Down Expand Up @@ -613,7 +651,7 @@ Name-Defining Constructs and Inheritance</h3>

For example,
given the following document
(using the imaginary <::shadow></::shadow> markup
(using the imaginary ''<::shadow></::shadow>'' markup
to indicate an element's [=shadow tree=]):

<xmp highlight=markup>
Expand Down Expand Up @@ -733,7 +771,7 @@ Serialized Tree-Scoped References</h4>

For example,
given the following document
(using the imaginary <::shadow></::shadow> markup
(using the imaginary ''<::shadow></::shadow>'' markup
to indicate an element's [=shadow tree=]):

<xmp highlight=markup>
Expand Down