[WICG/webcomponents] Web components should be able to easily adapt to the host page while maintaining enapsulation (Issue #986)

This originates in this [Twitter thread](https://twitter.com/LeaVerou/status/1629920779298127877) and this [Mastodon thread](https://front-end.social/@leaverou/109932592997927029).

### Problem statement

Components for encapsulating and packaging up blocks of functionality are usually composed from built-in controls, such as buttons and inputs, often recursively.
Host pages nearly always include base styles for all built-in controls, yet these components cannot take advantage of these styles without placing their elements in light DOM, which breaks encapsulation entirely. Furthermore, there is not even a straightforward way (either in CSS or JS) for these components to pull in styles from the shadow host. 

As a result, it is currently a nontrivial problem to create a web component that e.g. contains a text field and a button, and have that text field and button look like the other text fields and buttons on the surrounding page.

Yes, there is `::part()` and custom properties, but this means the host page needs to know which parts and custom properties the component uses, so currently authors need to spend a considerable amount of time integrating a component in their page, which makes it harder to mix and match components, and promotes monolithic component libraries that share the same styling conventions. There have been [some](https://github.com/castastrophe/wc-theming-standards) [efforts](https://github.com/webcomponents-cg/community-protocols) to standardize styling conventions, but nothing has caught up.

This also affects built-in components as well: e.g. `<input type=file>` has historically been annoying for authors because even though it includes a button, the button does not follow the page's button styles and needs to be styled separately.

This also comes up for non-interactive components: e.g. there are plenty of components for including Markdown in an HTML page, all suffering from the same problems: either they render Markdown in Shadow DOM and thus it looks out of place unless the page author spends a considerable amount of time duplicating their core styles for parts (assuming everything is actually exposed via parts), OR everything is rendered in the light DOM so it can be styled as normal, which means the original Markdown code is lost after the first render. 

There is the old [`open-stylable` Shadow Roots proposal](https://github.com/WICG/webcomponents/issues/909), but I think for most use cases component authors need more control than indiscriminately pulling in all styles from the host page.

### Potential solution

Essentially what we need is a declarative way for component authors to selectively opt-in controls to be stylable from the shadow host's styles, with certain restrictions so that you end up essentially only getting global styles intended for these controls (rules like `button`, `button:hover`, `input[type=number]`, `details > summary`), and not random ad hoc CSS code that would cause styling conflicts. I think the following restrictions would achieve that:

- Obviously, selectors involving combinators with unexposed parts of the shadow tree should not match, and selectors cannot cross shadow boundaries to match. 
- Certain attributes **cannot** take part in matching: `id`, `class`, `part`, `data-*` (any others?)
- Only [user action pseudo-classes](https://drafts.csswg.org/selectors/#useraction-pseudos) and [linguistic pseudo-classes](https://drafts.csswg.org/selectors/#linguistic-pseudos) can take part in matching, not [structural pseudo-classes](https://drafts.csswg.org/selectors/#structural-pseudos).
 - We don't want things like `:nth-child()` to match, do we? Unless we want to be able to pull in styles for more complicated structures like entire tables — do we want to cover this type of use case?

The opt-in mechanism would likely be an attribute, name TBB. Some (poor) ideas: `hoststylable`, `importstyles`, `allowhoststyles`. Hopefully we can find something shorter than these. The idea being that the attribute would start as a boolean attribute, but could in the future be expanded to take values for customizing the behavior.

### Open questions

- How does this attribute work across nested shadow roots? Do we need an explicit opt in (akin to `exportparts`) or do we just define it so that matching styles from all parent shadow hosts apply? It seems like the latter could better preserve intent.

-----

I'd love to hear from implementors: would something like this be feasible? How much implementation effort would it require? Are there any changes that would improve implementability?

-- 
Reply to this email directly or view it on GitHub:
https://github.com/WICG/webcomponents/issues/986

You are receiving this because you are subscribed to this thread.

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

Received on Monday, 27 February 2023 18:10:43 UTC