Re: [csswg-drafts] [css-scoping] Allow elements to expose a subset of their shadow tree, which can then be styled with regular CSS (#10939)

I definitely like where this proposal is going! The idea of creating a subtree of exposed elements/subtrees is a great idea imo.

I worry that as it stands right now, this proposal might cause:

- component consumers to write (be able to write) selectors that would be very brittle in real world scenarios
- component authors lots of backwards compatibility burden for elements that use the `export` attribute

I'll provide some more details below

### Brittle selectors

I'll agree that being able to write complex selectors, including relationship selectors, would be hugely beneficial over todays implementation of parts. However, if component consumers write selectors that depend on other characteristics of the exported element, then those selectors are immediately brittle for changes to the component later on.

Any kind of selector in the shadow root can't necessarily be depended on to always exist. A `<button>` may one day become an `<a>`, a `<div>` turn into a `<span>`, etc. Likewise, classes, IDs, attributes and any other characteristics of exported elements would be considered, in the vast majority of situations, to be "internal" to the component. In any kind of middlingly complex component, the internal architecture of elements, classes and attributes won't be part of the public API of the component like DOM properties, methods, and events are.

Personally speaking, I've never devoted exhaustive testing to make sure that certain css classes are on certain elements in the shadow root, unless thats the only way I have to test a public API feature. Therefore, any css selector used to style an exported element will instantly break when any of those selectors no longer exist on that exported element. Component authors will make hundreds of internal-only type changes that restructure the shadow root template without changing the public API of the component in a breaking way.

IMO, a solution to theming shouldn't encourage component consumers to rely on internal structure because it makes those styles very easily breakable in a way that will be very difficult and tedious to discover and fix. Anyone that writes selectors like the above will have to examine the new contents of the shadow root of the patch-bumped component to find what changed and how in order to fix their theme styling selectors accordingly.

### Backwards compatibility burden

With the `export` attribute relying mostly on the dom elements themselves, and allowing for component consumers to use the full power of css comes a very heavy burden on component authors. So much so that I fear that authors would shy away from theming this way. Adding the `export` attribute as described above would basically make adjusting ANYTHING about that element, classes, ids, attributes, and the element tag itself a breaking change. If relationship selectors were allowed, then by extension any change to that subtree relationship would ALSO be a breaking change. Component authors couldn't add another `export` sibling element between two existing elements because some consumer, unbeknownst to the component author, might have written an `nth-child(2)` selector referring to one of the existing exported elements.

This would mean that component authors would have a LOT more breaking changes to think about.

### Proposal

I love the idea of the subtree and the attribute to denote exporting the element to create it, but I think it needs some stable identifier that CAN be a part of the public API of the component without being related to the actual shape of the dom itself. Imo the stable identifiers are part of the good part of css parts. (lol, "parts" has no meaning to me now)

Currently a CSS part is just a name. Its not an element, class, or attribute. A component author can move the name around in the DOM independent of styles, attributes, IDs, or elements. For this proposal, I think it would be important to do the same. There needs to be an independent identifier associated with each exported thing. Unfortunately, I think that the issue with stable identifiers might also mean that exporting a whole subtree might not be tenable?

What if the subtree was not a tree of DOM elements, but was a "part tree" constructed of part names and not elements? IMO that could be what `exportparts` maybe should have been? Each element with an `export="{identifier}"` gets assembled into the exposed subtree as described above, but the css consumers would write wouldn't be using element/class/id/attr selectors, it would be using part selectors?

```html
<foo-spinner>
 <template shadowrootmode="open">
  <div class="wrapper" export="actions">
   <input export="main-input">
   <div class="buttons">
    <button class="increment" export="plus-button">+</button>
    <button class="decrement" export="minus-button">-</button>
   </div>
  </div>
 </template>
</foo-spinner>
```

```html
<foo-spinner>
 < :: exposed parts tree >
  :part(main-input)
  :part(plus-button)
  :part(minus-button)
 < / :: exposed parts tree >
</foo-spinner>
```

and css like:

```css
my-component >>> :part(main-input) + :part(minus-button) { /* some thing */}
my-component >>> :part(actions):has(:part(minus-button)) { /* some thing */}
```




-- 
GitHub Notification of comment by michaelwarren1106
Please view or discuss this issue at https://github.com/w3c/csswg-drafts/issues/10939#issuecomment-2375565078 using your GitHub account


-- 
Sent via github-notify-ml as configured in https://github.com/w3c/github-notify-ml-config

Received on Thursday, 26 September 2024 01:37:18 UTC