-
Notifications
You must be signed in to change notification settings - Fork 376
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Provide a lightweight mechanism to add styles to a custom element #468
Comments
I like this idea a lot. One thing about it that it solves is the issue of wanting to supply a "UA stylesheet" for your custom elements. You can't just do something like One thing I am still confused on is whether |
+1 from me on this idea; I'd wondered about an author-controlled "UA styles" a few years ago, early in the project, and this API surface feels good, better than whatever else I'd come up with. I presume that the selectors are meant to be interpreted "like" a shadow stylesheet, right? So they only apply to the element and its contents, and don't leak out to the global level? In that case this is pretty easy - just need to specify that the styles are interpreted in the user-agent origin and all of its selectors are scope-contained by the host element. I think using Question: do we want to necessarily tie this to the registerElement() call? Or do we want to allow embedding this into your global CSS too, so that even if your JS is slow or broken, your page at least doesn't totally break? We'd put it under a |
See also #376 (closed), where I had a similar idea. |
I really like this idea too, though it might be worth having a custom element-specific stylesheet instead: let sheet = document.createElement('style');
sheet.textContent = ':host { display: block; }';
customElements.define("cool-element", CoolElement, { styleSheet: sheet }); This way you can retain a reference and add to, remove or modify the css rules in a familiar manner later if required. |
Yeah, having the IDL be |
Interesting! Do you think this more limited approach (just giving a stylesheet to a custom element) is sufficient, or do you still think we need the ability to target arbitrary elements with a compound selector? I can see arguments either way. (I think we need this current idea either way; providing default styles for a component is good and useful all by itself.) |
It looks that each solves the different use cases. If a selector used in "a stylesheet to a custom element" always has a ":host" pseudo class, both approaches might be able to address the original concern. If we can assume that ":host" is always used in a selector here, can we have a more lightweight approach? e.g.
customElements.define("cool-element", CoolElement,
{style: "* {display: block; } *[red=true] {color: red; }",
shadowtreestyle: ... /* if we still need this */ } ); Thus, I would like to limit more and more so that it can become style-engine friendly, ignoring a shadow tree in most cases. |
That sounds reasonable to me! I think I agree that if you want to style the custom element's contents more fully, you should probably be using a shadow tree. The behavior of styles in shadow trees already works pretty well. So this brings your idea from #376 fully in line with the idea from this thread; the |
Yeah, I do not have an intention to block this thread's idea. I'm totally fine to let |
From the conference: There's no real objection to this proposal, but it needs to be more worked out with respect to the CSS cascade and such before it can be properly reviewed. Another concern that was raised is that it would help if there was some kind of holistic overview to styling custom elements and shadow DOM since there appear to be several overlapping approaches. |
That makes sense. Here the scenarios we've run into so far that need styling:
#1 is this proposal - attach some styles to the element at registration time, they're treated as user-agent origin. #2 is stylesheets in the shadow root. #3 is custom properties, applied via var() and @apply. #4 I'm not sure about yet, but Hayato's idea addresses it. |
Which idea of Hayato are you referring for (4)? |
The one that he and I were talking about immediately prior to this, from issue #376. |
@sorvell, does @hayatoito's simpler approach in #468 (comment) fit your use cases, or do you also need to be able to style descendant elements? @tabatkins, would you have some time next week to work on defining this (either @hayatoito's proposal or something closer to the OP) as a more fully-fleshed-out proposal, with maybe some proto spec text? I think we'd need your help (or someone else great at writing CSS specs) to actually figure out how this means, and maybe put the relevant stuff in CSS scoping. How I envision this is HTML just defining the dictionary member and saying something like "this creates a custom user-agent stylesheet for the current Window with element name name," where you can define "creates a custom user-agent stylesheet" for us. |
Yeah, def. |
@domenic Yes, I think #468 (comment) is a reasonable simplification. To be clear, I do not think it's a good idea to expose the ability to style descendants (children). The initial proposal did include styling shadowRoot elements (shadowRoot children), but this can always be addressed in the traditional way. Since you're already making a shadowRoot in that case putting a style element there is straightforward. @hayatoito's approach solves the fundamental problem here: an element has no desire to create a shadowRoot and just wants to style itself cheaply and easily. |
What about some options to disable all default UA styles? el.createShadowRoot({defaultStyles: false}) |
From my lesser understanding of all Web Components compared to you all, it seems as though ShadowDOM roots are designed to be the units of encapsulation for DOM. If that is the case, it seems like encapsulating styles in this programmatic manner might be a better fit for the el.createShadowRoot({styles: ':host {display: block; }') This particular example seems to make more sense because TLDR, would it make sense to move this programmatic definition of a style onto shadow roots where style encapsulation already exists, instead of on Custom Elements where we have to define new mechanisms to deal with possible ambiguities and style scoping issues? |
There is at least one case when it is not possible - when you extending native elements. They have UA's ShadowRoot, but you neither have access to it, nor have ability to create new one on them, look at #376 for more discussion. Also this particular issue is exactly about avoiding performance overhead of creating Shadow Root (see the first message in this thread). |
@nazar-pc Thanks for pointing that out. Maybe we can have both? customElements.define("cool-element", CoolElement, {styles: '.thing { color: blue; }');
el.createShadowRoot({styles: ':host {display: block; }') // using :host makes sense here |
@domenic All right, first draft is up. I forgot to give the heading an ID, so just visit https://drafts.csswg.org/css-scoping/#shadow-dom and scroll up. Let me know if this suits your needs and if you need anything changed. Idea is that DOM would parse the string to a stylesheet and then manipulate the |
@tabatkins that looks great! Where's the algorithm for parsing a string into a spec-stylesheet that I can use as the value in a map entry? |
@emilio Yeah I should have been more clear, in the example case since there is no specificity difference then it is resolved by the order. In the case you mentioned where the default style has higher specificity than styles in the shadow root, the default style would win.
I'm not sure I understand your first question, but it is using the shadow cascading order, so default style is in the same step as shadow styles. |
Your first reply answered my question, thanks! :) So specificity just works normally... which means that |
An alternative is to go ahead and put these in the UA origin, but disallow |
But then the author of a component can't specify |
I think it would be worth reconsidering the cascading order of "Custom Element Default Style" of the proposal. Currently, it is defined as:
however, we've seen several feedback arguing this rule is unfortunate. Given that, we might want to make it better so that web developers wouldn't encounter specificity issues. Remember that there are also several requirements mentioned in this thread, as such:
To make it better and satisfy these requirements at the same time, how about adding new origin, "custom elements default style declarations" to origin and Importance, as follows?
Then, I think we can satisfy requirements:
Blink is interested in implementing this idea, adding this new origin, "Custom elements default style declarations", and would like to see how things are going well and get feedback from web developers. We are aware that there was an objection to adding new origin, however, we couldn't think of any other ideas, as of now. |
TPAC F2F: There is no agreement on the latest proposal in #468 (comment) because of Apple's concern for the developer ergonomics and performance impact. Google offered to conduct an origin trial to gather more developer feedback. |
Again, I can't emphasize enough our objection for using a new cascading order. This feature was originally proposed as a way of avoiding the performance penalty to have a shadow root. Introducing a new cascading order would totally defeat that performance benefit by introducing more complexity and performance cost in our implementation. In general, this issue has morphed into a feature which lacks a clear list of use cases and instead of a solution looking for use cases to back that up. We need to re-enumerate a clear list of concrete use cases this feature is supposed to address since the proposed solution and the original problem make no sense whatsoever at this point. |
Is there any real benefit to this feature over just pushing a sheet into EDIT |
Thanks. We have to add style rules to every node trees' For the latter part, #769 could be related. |
Could you clarify the use case for a component author overriding |
For example, some components may not function when |
I suppose the |
All of my custom elements except for one, have styles but no shadow roots and do not distribute any children. Currently I'm applying styles using JSS directly to all of their Applying these styles via the custom element definition would be great! |
Now that I think about it, I think something like a |
@rniwa in order to solve the override problem, what if a new CSS function were introduced to allow an author to define permitted styles for an element? e.g. :host {
display: allow(block, inline-block, none);
writing-mode: allow(horizontal-tb);
/* special interaction with minmax() ? */
--column-width: allow(minmax(10px, 300px));
} The function could be special-cased to only be valid in the UA origin (to be compatible with @tabatkins's suggestion of making the styles work like UA defaults), but override even This way, you don't need a new stacking order and you can define a subset of permitted values for the props that matter. It would also provide reasoning for UA elements that behave this way already, such as setting |
@sorvell FYI I downvoted your original post not because I don't like the idea, but because I think that passing class-specific stuff into a non- |
I think it would be cool to give us the option to include multiple stylesheets on a web component. I can imagine a usecase where someone would want to include a css library + some custom rules on his web component. Lets say I create a web-component library and I want to use bootstrap + my own project-wide stylesheet. |
@alkismavridis that's possible via the |
@justinfagnani is there a resource/link where the successor or changes to adoptedStyleSheets are discussed? we also use it heavily in our code and I want to stay up to date :) |
@mzeiher FYI, there is a recent update here WICG/construct-stylesheets#45 (comment) |
Proposal
Allow a user to define a set of styles to apply to a custom element as an option to
customElements.define
. Conceptually, providing styles would make the element act as if it had ashadowRoot
including astyle
element with the provided css. The rules used to target the element would be the same as in Shadow DOM.Discussion
To style a custom element that does not otherwise need a
shadowRoot
incurs an unfortunate performance penalty and is cumbersome. A user must create a shadowRoot and put inside it astyle
element and aslot
element. Providing this styling at define time gives the platform an opportunity to optimize beyond what could be achieved when interpreting user code that installs the shadowRoot, style, and slot at construct/connected time. In addition, because the proposed syntax is less code than the alternative, it would likely reduce concern over #426.Ideally, developers could include
styles
targeting elements inside Shadow DOM in addition to the element itself. Again, the providedstyles
would act as if they were in astyle
that was the first element inside theshadowRoot
. This could help address #282 and the feature could be explained as a constructable stylesheet when this feature is added to the platform.The text was updated successfully, but these errors were encountered: