Re: [w3c/webcomponents] Theming options for shadow roots (#864)

The Polymer team has had some very interesting discussions with our sister Material Components team, which has lead to a bit of a change in perspective on this topic for me.

I think there are two broad categories of component authors, wrt to encapsulation and theming:

* Those that encapsulation is a bit of a hinderance to. They are asking for ways to open up shadow roots to styling. For LitElement users they are often using our feature that let's them turn off rendering to shadow roots (this often has a downside in that they still want to use `<slot>`, something clearly not possible). `::part()` and something like `::theme()` are a potentially solutions to them, for a middle-ground of incrementally breaking encapsulation.
* Those that encapsulation is important to for maintainability. Material Design and other design systems "at scale" probably fit into this category. Anything that the design system allows to be styled is a public interface that needs to be maintained, at potentially a large cost. `::part` may be too broad for these authors, as it allows stylings any property. Interestingly, even individual CSS custom properties that map to specific built-in CSS properties may be too broad, because they allow for any value, some of which may be invalid. These authors want theming and customization to be expressed in terms of their design system's design token (basically variables) abstractions.

This last point is really interesting to dive into. For example, in Material Design there are `elevation` and `density` parameters (aka design tokens). They are both enums that get exposed as a number of CSS properties applied to a number of implementation elements within various component's shadow roots. `elevation` may effect the box-shadow length of some elements, but the authors do not want to allow users to directly and arbitrarily set the box-shadow. 

The interface they want is basically:

```css
mwc-card {
  --material-elevation: 2;
}
```

_Not_ (imaginary expansion to properties, since I don't know the real ones):

```css
mwc-card {
  --material-box-shadow-length: 8.4;
  --material-card-background-dark: rgba(255, 255, 255, 0.25);
  /* ... */
}
```

SASS mixins let them do this because they can write mixins that transform logical values into concrete properties and tell users to only style components with the mixins.

In building web components using shadow DOM, then team is transforming the mixins to produce sets of CSS custom properties, so that component consumers can use the mixin with logical values, which are expanded to low-level specific values that pierce shadow roots.

Something like:
```sass
mwc-card {
  @include elevation(2);
}
```

This will produce the undesirable output with low-level above, but the expectation is that no one writes those properties by hand.

This seems like an ok interim approach, because components do not have to modify their own CSS to be themeable. It's not great because components do have to accept many low-level properties, the validity of the properties can't be checked, and the ergonomics are only good if using SASS.

The upshot is that the Material and Polymer teams would love to see some movement towards more SASS-like features to enable customization via logical, component-defined properties, as in:

```css
mwc-card {
  --material-elevation: 2;
}
```

I think this comes down to a number of semi-independent areas worth exploring:

1. **Expressiveness**: Transforming logical values into concrete properties requires more powerful calculations that CSS has. Conditionals and boolean operations are very important. Maybe some sort of look up system. Element queries have a number of important uses too.
2. **Abstraction**: Mixins of some sort seem like they solve the code-sharing problem very well. They are important for component authors to share the functions that transform logical values into concrete values. Examples seem to utilize mixins to produce single property values, sets of name/value pairs, and sets of rules with selectors.
3. **Modularity**: For CSS code sharing, developers want to be able to import mixin and variable definitions. I think something like the [CSS References proposal](https://github.com/w3c/csswg-drafts/issues/3714) could address this.
3. **Extensibility**: There is some desire to do styling work in JS. Style observers and/or custom CSS functions in JS would be useful here. I realize this is quite a big lift though.

These discussions were very enlightening to me, in that this design system team didn't really want `::theme()`. I think there are still other good use cases for `::theme()`, especially with "white label" components that want to allow many things to be styled arbitrarily (like [ING's Lion Components](https://github.com/ing-bank/lion)), and for "standalone" like video players and such.

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

Received on Friday, 20 March 2020 21:48:02 UTC