Open michaelwarren1106 opened 3 months ago
Pasting my comment:
- "As a component author, I want to build unstyled components that only manage behavior. I want to give my consumers full control and achieve maximum compatibility with their existing styling solutions. I am ok with the tradeoff that DOM changes can break consumer's styles."
- "As a website author, I want to use shadow DOM for my own components (that I author and consume myself). I want to use my existing CSS system, including any global resets, utility classes, and hand-rolled scoped classes. Crucially, I want these styles to be usable in DSD without causing FOUC."
From shadow layers proposal (noting they may be a bit over-broad particularly as to coordination scenarios):
From shadow layers proposal (noting they may be a bit over-broad particularly as to coordination scenarios):
Use Cases Addressed
- Include all document CSS as a low priority layer inside a shadow tree. This is the heart of a solution to the original issue as opened.
- Support both declarative and imperative use. Declarative shadow trees are fully supported from the onset, as well as imperative use cases.
- Include selected document CSS as a layer inside a shadow tree. Selected named outer layers can be brought into a shadow tree by either a shadow tree designer or shadow tree user.
- Enable layer reprioritization. Inner and outer context layers can be intermixed and reprioritized.
- Enable shadow tree designers to bring in document CSS without intervention by a shadow tree user. If desired, a shadow tree designer can bring in all of or just selected layers of the document outer context CSS, without intervention of the shadow tree user.
- Enable coordination between shadow tree designers and shadow tree users. Either can bring in and repriortize outer layers.
- Enable shadow tree user to add and repriortize layers originally provided by shadow tree designer. A user can bring in any chosen outer layer, not just those pre-defined by a designer.
- Enable a shadow tree designer to "advertise" to shadow tree users the CSS priorities of a shadow tree's inner context. A designer can expose, publish, or document the original layer order of a shadow tree, so that a user can knowingly adjust it or add to it.
- Polyfillable. As hopefully implied by this proof of concept implementations.
these are great! would you mind taking a swing at framing these use cases in terms of user stories? i definitely agree that any solution must have some/or all of these baked in, but the current phrasing makes them sound more like features of a solution and less like stories that describe particular, specific user needs/wants.
Filtering as a potentially key requirement:
To me, the key open question that needs to be answered is whether selective adoption of document-level stylesheets is necessary or not. That is, should a component or users of the component need to be able to filter (i.e. selectively apply) which stylesheet or style rules apply to its shadow tree.
answering yes, filtering needed, with related essential requirements:
Use cases are intertwined.
Whether simple (I just want my page resets to work in my shadow tree) or most painful (component and context are controlled by different entities) or in between, use cases trace to the same shadow encapsulation, and loosening encapsulation will likely impact many if not all in some way.
Declarative shadow DOM is required.
To me, declarative shadow DOM is required from the onset not just because it is a new thing so logically it must be supported too, but because shadow trees are just HTML and they are what are doing the encapsulating to loosen. And they are a part of the solution.
So Javascript-only solutions are basically out. And polyfillability though not a strict requirement is in this case something of an acid test for completeness.
But also declarative shadow trees already by design address opt-in for imperatively-created web components.
Context-aware opt-in protection is needed.
I don't think an opt-in flag or mode that just brings in all page styles would work as expected in all cases. Some shadow styles could unexpectedly lose. Or get pulled back into a specificity race that could feel like shadow trees just gave up.
Prioritization is required.
Or maybe just unavoidable, since unlayered styles are of necessity assigned a layer priority. And a limited form of priority for shadow trees already exists in the context step, so any brought-in styles would pass through that step too.
Declarative shadow DOM is required.
To me, declarative shadow DOM is required from the onset not just because it is a new thing so logically it must be supported too, but because shadow trees are just HTML and they are what are doing the encapsulating to loosen. And they are a part of the solution.
So Javascript-only solutions are basically out. And polyfillability though not a strict requirement is in this case something of an acid test for completeness.
What are concrete user scenarios that necessitates declarative shadow DOM support? i.e. what exactly is one building to encounter this need?
Context-aware opt-in protection is needed.
I don't think an opt-in flag or mode that just brings in all page styles would work as expected in all cases. Some shadow styles could unexpectedly lose. Or get pulled back into a specificity race that could feel like shadow trees just gave up.
Again, what are concrete user scenarios that necessitates context-aware opt-in?
Prioritization is required.
Or maybe just unavoidable, since unlayered styles are of necessity assigned a layer priority. And a limited form of priority for shadow trees already exists in the context step, so any brought-in styles would pass through that step too.
Again, what are concrete user scenarios that necessitates prioritization of CSS rules?
Filtering as a potentially key requirement:
To me, the key open question that needs to be answered is whether selective adoption of document-level stylesheets is necessary or not. That is, should a component or users of the component need to be able to filter (i.e. selectively apply) which stylesheet or style rules apply to its shadow tree.
answering yes, filtering needed, with related essential requirements:
Use cases are intertwined.
Whether simple (I just want my page resets to work in my shadow tree) or most painful (component and context are controlled by different entities) or in between, use cases trace to the same shadow encapsulation, and loosening encapsulation will likely impact many if not all in some way.
Declarative shadow DOM is required.
To me, declarative shadow DOM is required from the onset not just because it is a new thing so logically it must be supported too, but because shadow trees are just HTML and they are what are doing the encapsulating to loosen. And they are a part of the solution.
So Javascript-only solutions are basically out. And polyfillability though not a strict requirement is in this case something of an acid test for completeness.
But also declarative shadow trees already by design address opt-in for imperatively-created web components.
Context-aware opt-in protection is needed.
I don't think an opt-in flag or mode that just brings in all page styles would work as expected in all cases. Some shadow styles could unexpectedly lose. Or get pulled back into a specificity race that could feel like shadow trees just gave up.
Prioritization is required.
Or maybe just unavoidable, since unlayered styles are of necessity assigned a layer priority. And a limited form of priority for shadow trees already exists in the context step, so any brought-in styles would pass through that step too.
i understand all of these as possible solution requirements. in order to frame them, i would still love to see each of these connected to a direct user need in terms of the typical user story framing.
how do these items get put into a sentence like:
“As a {person} i would like {feature/requirement} so that I can {do a specific thing}.
i think this exercise and framing will help tie stuff like “prioritization is required” to a direct reason WHY prioritization is required in terms of a person and their ability/non-ability to build things.
Two non-mutually exclusive use cases concerning styling shadow DOM elements from outside the component that I wish can be supported (but not sure if they can be part of this initiative/proposal):
EDIT: On second thought, they might be mutually exclusive, not sure 🤔
Here's an attempt at counting how many of these user stories imply a need for:
User | pull | push | layers | combinators |
---|---|---|---|---|
@mayank99 | 2 | 0 | 1 | 0? |
@zaygraveyard | 0 | 1 | 0 | 0 |
@darkwiiplayer | 2 | 0 | 2 | 1 |
@knowler | 1 | 0 | 1 | 0 |
@robglidden | 1 | 2 | 1 | 0 |
Total | 6 | 3 | 5 | 1 |
I will attempt to update this list as more user-stories come in (as time allows). Feel free to suggest additional considerations to track.
When developing web applications for company-internal use, I want to re-use web components that represent common logic across various projects regardless of what tech stack they individually use. When frameworks are used that require extra classes, I want to extend the components to use templates and have the framework classes available automatically inside the component.
@michaelwarren1106, @rniwa:
It seems to be getting missed that modern browsers support "Declarative Shadow DOM".
The "user" in the above use cases and requirements is just the user of a shadow tree, particularly a declarative shadow tree.
To elaborate:
Declarative shadow DOM already gives web component users a way to present a shadow tree (with user-written CSS styles in it) to the web component. And a way for the web component to accept, reject, or use those styles as it sees fit.
So user stories that boil down to something like "as a web component user I want the web component to consider using some styles I present to it in a shadow tree" is not a missing platform feature, it is a choice for web component authors to make.
What is missing is a way to bring page styles into shadow trees.
Without this common context, there seems to be a conflation loop.
Classifying as "push" vs "pull" vs "other" seem to suffer similarly.
user stories that boil down to “as a user i need X so that Y” is precisely for the purpose of making sure we don’t conflate things and are crystal clear about what to ask implementers for and why.
if the user stories you are thinking of are more specific than “as a web component user” then that’s great! let’s capture those under a different persona. like “as a developer using shadow trees with declarative shadow dom, i need X so that Y”.
what i think implementers are asking for, and the purpose of my creating this issue is about finding all the Xs and the Ys.
we all have different opinions on the “what do people want” it’s the “so that Y”s that really matter. specifying what devs are unable to do today, or what things are difficult/cumbersome today is the entire reason to change things. calling some feature being “a missing platform feature” isn’t as powerful as describing specifically what that new feature will accomplish that matters.
in the other thread, and now starting in this one, there’s been a lot of “i think it should be this way” and not enough “if it is {this way} then {persona} can do {thing} way easier/simpler/faster/better etc etc“.
we need to get at the specifics of what folks are trying to do. enumerate those first. THEN work on solutions that solve those cases. as of yet we’ve been working backwards from opinions about things we think are needed and not working forward from actual outlined spelled out problems.
@robglidden
It seems to be getting missed that modern browsers support "Declarative Shadow DOM".
Declarative Shadow DOM is an optimisation to avoid FOUC by pre-rendering the contents of a shadow DOM on the server or during deployment. It's not an entirely new way of doing shadow DOM, just an additional API to attach and initialise it. The problems with styling remain the exact same ones: Outside style-sheets don't affect the insides of the shadow DOM.
- Shadow trees are not "Custom Elements"
I think you're missing the forest for the trees here, no pun intended. Shadow DOM is primarily useful in combination with custom elements and <template>
s to build web components. They can be attached to other elements, yes, but that is a very rare way of using them, so it makes sense for most of these user stories to focus on this main use-case.
If you have any user stories that showcase the use of shadow-dom with normal HTML elements, I'd be curious to see those to get another perspective on the spec, but if you don't actually post them here, then we can't read your mind.
So user stories that boil down to something like "as a web component user I want the web component to consider using some styles I present to it in a shadow tree" is not a missing platform feature, it is a choice for web component authors to make.
It is not per se a missing feature, as it can be done imperatively using Javascript, but it is a common enough case for a specific platform feature to be added to make it more ergonomic and resilient. Synchronising stylesheets between light- and shadow-dom is far from trivial with the APIs we currently have.
Classifying as "push" vs "pull" vs "other" seem to suffer similarly
I disagree. Classifying as "push" vs "pull" is very important because it is the distinction between whether the component author or the component user is the one who initiates the style adoption. The open-stylable proposal specifically addresses the former case, where a component author wants to opt in to some or all styles defined by the component user. It preserves encapsulation except where the author specifically chooses to expose APIs to let the user influence the process.
Separating user stories into which of the two they need is important to know whether a push-based mechanism is worth exploring further, either as a separate feature, or as a part of open-stylable, or a purely pull-based mechanism can cover most of the users' needs.
Again, if you think there's another, more important axis to consider, it'd be much easier if you could explain it with some actual user stories or at least specific use cases. I think this issue was created precisely because just listing requirements seems a bit arbitrary to us strangers on the internet, and user stories are a convenient way of bundling a requirement with the context to show why that requirement is useful.
@michaelwarren1106:
No objection from me, user stories are valuable.
I am saying something different.
The primary use case #909 was opened for in 2020 is component library maintainers who want to move to web components while supporting stylesheets that they don't control. And there are important related use cases.
But now, years later, declarative shadow DOM directly addresses many of these related use cases.
In particular, declarative shadow DOM already provides a way for web component users to present user written styles to web components. In a way that answers the often-expressed need on behalf of web component authors to have opt-in say before accepting those styles into web components.
So I am saying it doesn't make sense to collect user stories for something that was already considered and implemented in web browsers. To me, the problem to solve is bringing page styles into shadow trees, not some other already solved problem.
So no, I am not saying or implying at all that I am thinking of (or being cagey about) user stories that are more specific than "as a web component user". That's backwards.
@DarkWiiPlayer:
Declarative Shadow DOM is most powerful when used with "Custom Elements".
Declarative shadow trees were designed exactly to support the case of web component users presenting shadow trees to web component authors to consider using in a more declarative, ergonomic, resilient, and component-author-acceptable way than imperative Javascript.
To me that's the other, more important axis to consider.
That's not really use cases / user stories. Use cases are specific scenarios in which specific piece of software may be used in a specific way, not some general statement about what kind of problem ought to be solved.
"as a web component user I want the web component to consider using some styles I present to it in a shadow tree"
That is the user story that is already asked and answered by declarative shadow DOM.
I don't understand the relationship of declarative shadow DOM to the discussion here.
As an implementation detail, not a user story, any new mode or option to attachShadow()
would be available as an attribute on the DSD template. Other than that, shadow roots created imperatively and declaratively are basically the same. Open-stylable would obviously be available on both.
Users of a component being able to provide their own shadow root to a custom element is, honestly, a pretty niche use of shadow DOM. I know of no components written this way and I wouldn't want to have to resort to this - which would interfere with the component having it's own shadow root - as a way of theming components. We should be able to do better.
But also... theming is different from open-stylable. Open stylable is a proposal to solve a problem affecting components migrating from light DOM to shadow DOM. There are still lots of other problems around theming that are better solved, IMO, with specific theming APIs that don't require completely opening up a shadow root to styles, and work with ::part().
edit:
Declarative shadow trees were designed exactly to support the case of web component users presenting shadow trees to web component authors to consider using in a more declarative, ergonomic, resilient, and component-author-acceptable way than imperative Javascript.
This is historically incorrect. Declarative shadow DOM was designed to support server-side rendering of shadow roots. Their main use case has been as a serialization of shadow roots that would have been created with attachShadow()
- ie, as an internal component feature. In fact, some of the discussion was around how to mitigate the hazard of users placing shadow roots on components they don't own and therefore breaking the component. They were not designed for ergonomics or to be in any way more "component-author-acceptable" than attachShadow()
.
i feel like i should just close this issue and try to compile user stories elsewhere. this issue is rapidly turning into another debate about solutions and proposals instead of merely listing problems needing solving.
we don’t need another thread for debating proposals, terms and concepts. that will just derail any progress
@justinfagnani:
Declarative Shadow DOM can be used on its own as a way to encapsulate styles or customize child placement, but it's most powerful when used with Custom Elements.
is a direct quote from a Google web site.
Please, I would not want to be misinterpreted if I said "Google, meet Google". So I won't say it.
Please don't use this issue to discuss things. That's the point of https://github.com/WICG/webcomponents/issues/909. This issue should focus on collecting specific use cases.
User story: I’m building a web app. I’ve already written the styles for various user interface elements (e.g. buttons, form controls). Now I have a larger composition that I need to repeat throughout the app which includes a number of these elements (e.g. a modal dialog that includes a few buttons) and I would like to use the shadow DOM for this. Slots are the wrong tool for the job since the component doesn’t need the composition they provide. Parts are equally awkward since they require me to rewrite my CSS. I would love to write the styles for these elements once, then allow the web components in my app use them (ideally without requiring my entire stylesheet also be applied to the shadow root).
DSD used purely for example and some details might be left out:
```html
DSD used purely for example and some details might be left out:
```html
- Form associated elements won’t associate with any forms they are a part of—there would need to be extra logic written to make that work (i.e. making the wrapper element a form associated element). - Third party custom elements don’t know about my styled custom element, so this requires me to have the styles available to apply to parts that they might expose. - I don’t want to modularize my entire CSS component library just to use the Shadow DOM.
Any styles that are allowed into a shadow root will potentially match something in the shadow root, so I personally would like to restrict that to a minimum, since otherwise the benefits of the _isolation_ aspect of style encapsulation completely go away. For example, if I let all the styles in, then I both need to be more careful with how I write my document-level styles and more guarded with how I write my shadow root’s styles. By only allowing in what the component needs (it doesn’t have to necessarily use all of the allowed styles), then I am still able to enjoy all the benefits of style encapsulation and have some external styles to use for my component abstraction. Note that I am still very much interested in using the existing shadow DOM styling features (i.e. parts, slots, etc.) for styling _concrete_ uses of my components. If any of the concrete uses of my components need more access to its shadow root for styling (e.g. more than the parts API can provide), I would prefer to keep that as an exception and apply those styles specifically to the shadow root that they apply to. I find that this becomes a lot more maintainable since generally the concrete uses of the component are styled with a more robust and declarative styling API (e.g. `delete-dialog::part(confirm-button)`), while any exceptions are very clearly highlighted as being so.
@knowler : That's some good concrete use case, thank you! Could you elaborate why applying the entire stylesheet is problematic in your use case?
@rniwa just for clarification when you say "the entire stylesheet" do you mean "all of the page level stylesheets"? (or is it tree scoped, or something else?) It's the word "the" I'm asking about I guess. It seems to indicate that we've somehow identified a specific stylesheet, and I'm not sure if you meant that or not?
Here are user stories and corresponding Web Platform Tests for the collection of user stories #1052 for "open-stylable" Shadow Roots #909.
You can find the actual web platform tests in the shadow layers proposal repository.
@rniwa just for clarification when you say "the entire stylesheet" do you mean "all of the page level stylesheets"? (or is it tree scoped, or something else?) It's the word "the" I'm asking about I guess. It seems to indicate that we've somehow identified a specific stylesheet, and I'm not sure if you meant that or not?
I'm talking about the stylesheet referred to in "ideally without requiring my entire stylesheet also be applied to the shadow root". Not sure if knowler meant all of page's stylesheets, or a specific stylesheet imported by link
/ @import. I'd like to understand what use cases lead to the need to filter, or selectively apply, style rules because that seems like a key question here as I mentioned in https://github.com/WICG/webcomponents/issues/909 as well.
Could you elaborate why applying the entire stylesheet is problematic in your use case?
@rniwa I updated my comment above (under “Why not all the styles (the entire stylesheet or all the stylesheets)?”) to answer your question.
Not sure if knowler meant all of page's stylesheets, or a specific stylesheet imported by link /
@import
. I'd like to understand what use cases lead to the need to filter, or selectively apply, style rules because that seems like a key question here as I mentioned in https://github.com/WICG/webcomponents/issues/909 as well.
For the use case above, I meant that I don’t want all of the document’s stylesheets. That use case is more flexible in regards to how I structure/split up my stylesheets, so if I needed to split out the styles I want to be included in the shadow roots into a separate stylesheet, then I wouldn’t have any issue doing that. I guess one potential complication is that I am likely using layers in the document (especially to facilitate any code splitting), but in the shadow root I might have a different layering structure or no layering structure, so that would need to be considered if a singular mechanism for applying to styles to both the document and shadow root is used.
Inspired by the recent comment in the feature issue:
As a website author, I want to structure my CSS however works best for my project and make as little changes as possible to achieve compatibility with the web components I want to or may in the future want to use. When changes have to be made, they should be generic and semantic and not specific to the components.
As an added example: If I want a component <contact-form>
to inherit resets.css
and framework.css
from the light-dom, I should not be expected to somehow mark those two files as used by contact form, but at best instruct the <contact-form>
to use two files, and at worst mark those two files as "resets" and "basic styles / framework" in a way that works or can work for any other similar component from different authors.
In other words, every mechanism for selecting to use styles from resets.css
but not from footer.css
should work regardless of whether those two files are linked using a <link>
tag, an @import
tag or are inlined in a <style>
tag.
As a component author, I want to build components that default to inheriting all the outside styles, but allow users to narrow down what styles get inherited. I want to define my own API for this to have proper control over how much flexibility I want to give to my users.
As a component author, I want to inherit the outside styles not into the entire shadow-dom, but into a scope to make sure outside styles cannot mess with certain parts of my component like a top level grid wrapper. For example when populating the shadow-dom with my own HTML, then inserting generated HTML into that structure.
As a website author / component user, I want components to follow the surrounding theme and not end up with, e.g., a dark-mode contact form in a light-mode website or vice versa.
I bring this one up because it might depend on selectors like .dark button { color: white }
detecting a button
inside a shadow DOM attached to a descendant from a class="dark"
element. I suspect getting combinators to work like this might cause some massive headache to the browser people, so I want to make extra sure these problems get discussed as early as possible.
As a website author / component user, I want components to follow the surrounding theme and not end up with, e.g., a dark-mode contact form in a light-mode website or vice versa.
I bring this one up because it might depend on selectors like
.dark button { color: white }
detecting abutton
inside a shadow DOM attached to a descendant from aclass="dark"
element. I suspect getting combinators to work like this might cause some massive headache to the browser people, so I want to make extra sure these problems get discussed as early as possible.
@DarkWiiPlayer Some of those cases are potentially solvable with container style queries using custom properties (e.g. @container style(--theme: dark)
). Not quite the same as using a class name, since they can be “intercepted” as they inherit down a tree (but in many ways that would be better for theming).
In any case, this is good to highlight, so thanks for bringing this up.
Here are updated user stories and corresponding Web Platform Tests for the collection of user stories #1052 for "open-stylable" Shadow Roots #909.
Additional user stories and corresponding web platform tests for the collection of user stories #1052 for "open-stylable" Shadow Roots #909.
As a shadow tree or web component user, I want to provide some page styles outside a shadow tree that won't affect the page at all but can be inherited into the shadow tree, so that I can write page styles that only affect shadow trees.
- Note that [when evaluated in the context of a shadow tree](https://drafts.csswg.org/css-scoping/#host-selector), `:host(Hi all, let’s make this a GitHub Discussion: https://github.com/w3c/webcomponents-cg/discussions/92
I think that format will help us keep individual user stories surfaced and will allow us to as further questions to clarify each use case.
Feel free to move your use cases over there. I’ll circle around in the next week to collect any that have been missed.
Here are additional user stories and corresponding web platform tests for the collection of user stories #1052 for "open-stylable" Shadow Roots #909.
Here are additional user stories and corresponding web platform tests for the collection of user stories #1052 for "open-stylable" Shadow Roots #909.
```
34 Component library with declarative and imperative components and page styles
As a shadow-tree-based component library author or maintainer starting from the component library in "33 Component library with CSS file and page styles", I want to add declarative-only components (components built with declarative shadow DOM and no Javascript), so that the library provides both declarative and imperative components.
Exemplar declarative component:
- **`H2 outside shadow tree
35 Component library with multi-component user-settable lower and higher priority page styles
As a shadow-tree-based component library author or maintainer starting from the component library in "34 Component library with declarative and imperative components and page styles", I want to add multi-component user-settable lower and higher priority page styles, so that users can provide page styles that have either lower or higher priority than component default styles.
```html
H2 outside shadow tree
36 Component library with individual component user-settable lower and higher priority page styles
As a shadow-tree-based component library author or maintainer starting from the component library in "35 Component library with multi-component user-settable lower and higher priority page styles", I want to add to individual components user-settable lower and higher priority page styles, so that users can bring in and priortize any page style layers they want.
```html
H2 outside shadow tree
All,
I've spent some time going through the use cases and trying to organize and categorize them in a way that might be useful in discussions with browser implementors. I tried to analyze and combine similar use cases into representative use cases and categories. I've also disregarded any use cases that I thought were pointing too directly at a solution like "I want to use css layers to do ...." or "I want to use @sheet to push styles into a component". Personally, I don't think use cases should pre-dispose solutions, only describe problems that are currently difficult to implement in today's world. The solutions discussions come after the use cases, imo.
Here's what I have come up with.
Inherit styles from a parent root instead of the document
<body>
element.Open Questions / Use Cases / Features of a solution?
If I've missed (or disregarded) your use case, and you feel it important to include and appreciably different from the ones captured above, I'm happy to amend the list. If you can phrase your use case in the "As a , I want __ so that " format without pre-supposing a solution/approach, I'll add.
Thanks for summarizing @michaelwarren1106 🙂 Slight nit on the DSD out of order streaming summary:
- requires a shadowRoot on the element.
+ requires a shadowRoot on the body element.
Thanks for summarizing @michaelwarren1106 🙂 Slight nit on the DSD out of order streaming summary:
- requires a shadowRoot on the element. + requires a shadowRoot on the body element.
haha i had it as html and github ignored it hehe. put backticks around it
Let’s let this issue serve as the single place to collect user stories around the “open-stylable shadow roots” proposal.
https://github.com/WICG/webcomponents/issues/909
Submit user stories as comments and I will do my best to collate theme here in this top comment for easy viewing/referral.
User Stories