w3c / w3c/csswg-drafts

[css-scoping] Consider aligning ::slotted() for fallback content with implementations

Open
#5,482 7 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

css-scoping-1 Needs Edits Needs Testcase (WPT)
Dominant language
Bikeshed
Stars
4.9k
Forks
816
PR merge metrics
PR metrics pending

Description

The scoping spec states that:

"The ::slotted() pseudo-element represents the elements assigned, after flattening"

According to the flattening algorithm in the HTML spec, that also includes the fallback children of a slot if that slot has no assigned nodes. This behavior was agreed on in WebComponents issue 631 and issues were reported for Blink and WebKit, but have not been fixed.

The current implementations walk the assignedSlot chain and apply ::slotted rules from each slot's scope, assignedSlot being null for fallback elements.

This is an example of how this works (in all browsers per current spec) with nested slot assignment:

<!doctype html>
<div id="host"><span class="a">Orange with blue border</span></div>
<script>
  const root = host.attachShadow({mode:"open"});
  root.innerHTML = `
    <style>
      ::slotted(.a) { border: 2px solid blue }
    </style>
    <div id="host">
      <slot></slot>
    </div>
  `;
  const inner_root = root.querySelector("#host").attachShadow({mode:"open"});
  inner_root.innerHTML = `
    <style>
      ::slotted(.a) { color: orange; }
    </style>
    <slot></slot>
  `;
</script>

Per current spec, moving the span into fallback content for the slot should also result in orange text and blue border, but this is unstyled in all browsers):

<!doctype html>
<div id="host"></div>
<script>
  const root = host.attachShadow({mode:"open"});
  root.innerHTML = `
    <style>
      ::slotted(.a) { border: 2px solid blue }
    </style>
    <div id="host">
      <slot><span class="a">Orange with blue border</span></slot>
    </div>
  `;
  const inner_root = root.querySelector("#host").attachShadow({mode:"open"});
  inner_root.innerHTML = `
    <style>
      ::slotted(.a) { color: orange; }
    </style>
    <slot></slot>
  `;
</script>

If the author wants to style a certain type of element the same whether it is assigned, or fallback, it can be accomplished with the current implementations adding an extra selector like this:

::slotted(.a), slot > .a

However, that only works in the scope where the fallback is. For the example above, you can do this for the tree with the border rule, but not when that slot is assigned to the slot of the inner root.

I have done an implementation which matches the current spec in Blink, and it is pretty straightforward. However, compat is a big concern here. The impact of changing the implementation would be hard to use-count/quantify. I've been in contact with engineers at Google working on Web Components and Polymer who thinks that changing this is too risky compat-wise and would prefer a spec change.

This surfaced in a bug report from Salesforce which found inconsistencies between implementations, but it turns out that is about ::slotted(slot) matching nested slots in WebKit, while Blink and Firefox do not match those:

<!doctype html>
<div id="host"><span class="a" slot="inner">Orange with blue border</span></div>
<script>
  const root = host.attachShadow({mode:"open"});
  root.innerHTML = `
    <style>
      ::slotted(.a) { border: 2px solid blue }
    </style>
    <div id="host">
      <slot>
        <slot name="inner"></slot>
      </slot>
    </div>
  `;
  const inner_root = root.querySelector("#host").attachShadow({mode:"open"});
  inner_root.innerHTML = `
    <style>
      ::slotted(slot) { color: orange; }
    </style>
    <slot></slot>
  `;
</script>

@emilio @rniwa @gregwhitworth

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the CSS scoping definition of ::slotted(), the HTML flattening algorithm, WebComponents issue 631, and the two reduced examples in the issue. Compare current browser behavior for fallback and nested slot assignment. Done means resolving whether implementations should change or the specification should, with the intended behavior agreed.

Written by the indexing model from the issue text.

Assessment

Tech stack
css, html
Domain
frontend, web-dev
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
28/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.