Re: [WICG/webcomponents] "open-stylable" Shadow Roots (#909)

I see two problems to be solved here:

1. Allowing consumers more control over styling
2. Allowing shadow roots to share styles

I think these have different, but similar solutions. First, a quick refresher about the “C” in CSS, because the cascade is fundamental to any solution proposed for this issue since it’s part of the problem.

## Quick refresher on the cascade

For those unfamiliar, here’s a simplified ordering of the cascade:

1. User agent styles
2. User styles (i.e. user preferences in the browser like font size, etc.)
3. Shadow context styles (i.e. the current shadow context)
4. Document or “host context” styles (which can be another shadow context)
    1. Parent’s shadow context styles
    2. Document styles
5. Inline styles

The shadow context’s styles being cascaded before its host context’s styles (e.g. the document or a parent’s shadow context) is _the reason_ that Shadow DOM styles set with `:host`, `::slotted()`, and for CSS parts appear “weak.”

[Cascade layers][css-cascade-layers] which are set with `@layer` are layers within contexts (i.e. a document can have its own layers and a shadow context can have its own). I propose we use cascade layers to help solve both of these problems.

[css-cascade-layers]: https://css-tricks.com/css-cascade-layers/

## Host layerable shadow roots (solution for problem 1)

This feature would **allow shadow roots to be positioned within the host context’s layers.** This would require two steps:

1. A shadow root would need to mark itself as host layerable. This could probably be done during registration or declaratively with a `shadowroot` prefixed attribute.
2. A consumer can use a CSS API for determining where they want to position the shadow root within their cascade layers (whether that be the document _or_ another shadow root).

Keep in mind the naming for the syntax in the following examples is _ad hoc_ and not the point.

Both of these examples will use two layers `defaults` and `components`. The `defaults` layer is what will apply to the specified shadow roots and the `components` layer will not apply. Here’s the ordering we achieve:

1. `defaults` layer
2. The specified host layerable shadow roots (e.g. `my-element` and `another-element`)
3. `components` layer

The first idea is to use an `@` rule:

```css
/* Host context styles */
@layer defaults, components;

@layer defaults {
  /* Styles for stuff like buttons, etc. will apply to the shadow roots. */

  @shadow my-element, another-element;
}

@layer components {
  /* Styles set here will have no bearing on the shadow roots specified above */
}
```

The position within the layer wouldn’t matter—the shadow roots will always be cascaded after the layer. Admittedly, I think that would make this syntax potentially confusing.

Another syntax idea, which I prefer, is to use a function within the `@layer` syntax.

This could be done up front:

```css
@layer defaults shadow(my-element, another-element), components;
```

Or after the fact:

```css
/* Host context styles */
@layer defaults, components;


@layer defaults shadow(my-element, another-element) {
  /* Styles for stuff like buttons, etc. will apply to the shadow roots. */
}
```

Perhaps `shadow(*)` could match any element with a “host layerable” shadow root.

## Shareable prelude layers for shadow roots (solution for problem 2)

This feature would **allow shadow roots to share a common layer**. It is different than the above feature since it would allow shadow roots to still remain in the cascade prior to the document styles. It seems like this would be useful for allowing a shared library of components to share styles like resets, default custom properties, etc. The cascade would look like this:

1. User agent styles
2. User styles
3. Shared prelude shadow styles
    - Would only apply if the shadow context below opted-in to it.
4. Shadow context
5. Document/host’s context
6. etc.

I don’t think this it would make much sense to allow shadow roots to define these styles themselves, but instead allow them to be opted into (likely through imports).

I think others have shared some ideas for syntax that could apply here.

-- 
Reply to this email directly or view it on GitHub:
https://github.com/WICG/webcomponents/issues/909#issuecomment-1883480640
You are receiving this because you are subscribed to this thread.

Message ID: <WICG/webcomponents/issues/909/1883480640@github.com>

Received on Tuesday, 9 January 2024 17:26:05 UTC