I’m still a bit confused about the Vaadin styling mechanism.
We are using the component library standalone (no backend) and we would like to customize some Vaadin components globally (a theme).
The ideal situtation would be to define this in only 1 css file to only include a stylesheet once on the main document.
I think there are more options:
1 - css properties
Use css properties, like for example –vaadin-button-background
This can be done easily as css properties are global and affect all the components in the document.
I understand how to use them, but as a result of css parts only being exposed to the parent DOM this would mean we have to include the style sheet to every parent DOM we use the Vaadin component in which introduces a lot of boilerplate which also can be forgotten etc.
3 - registerStyles
We used to use the registerStyles concept that worked nicely, but this is not recommended anymore, see:
The advantage of this method was/is we only have to register a style once globally and this is applied to all the components. No need to add any styles on specific places.
A disadvantage is we have to think better about how to define the styling as the selectors are a bit different when styles in the shadow DOM, see:
My question is what would be the recommended way to do this and why is the registerStyles method not recommended anymore although this seems to be the most effective way without a lot of boilerplate (see remark in 2 - css selectors)
Is there any more documentation (or could there be?) on how to achieve this when using Vaadin components standalone?
I should probably preface the answer by noting that our documentation is focused on Flow and Hilla framework users, as those make up ~99% of the users of our components, and with those frameworks the theme folder approach is currently the best and easiest way to style them.
The shadow DOM injection approach is no longer recommended because it is, for the vast majority of users, more complicated than using style properties and normal light-DOM css with part selectors etc, and because it is likely to be incompatible with future version of the Vaadin platform.
For the just-components / no-framework approach, style properties and light-DOM css is also the recommended approach, and I’m a bit confused by this part:
I understand how to use them, but as a result of css parts only being exposed to the parent DOM this would mean we have to include the style sheet to every parent DOM we use the Vaadin component in which introduces a lot of boilerplate which also can be forgotten etc.
This is how CSS is usually used: you have a stylesheet that you load into the page one way or another. The ::part() selector is no different from any other normal CSS selector, there is nothing special about its scope. The “parent DOM” of a webpage is usually the page root (unless you’re using shadow roots within the rest of your UI, in which case the those shadow roots are the parent DOM, but then you’re kind of creating a problem for yourself, not just for styling Vaadin components, but for any styling).
Unless you’re building static html pages by hand, I’m assuming you’re using some kind of framework that has a way to ensure that the same stylesheet is loaded across all pages. So then you do have one css file, which you load to your UI using whatever mechanism you have.
I’d first like to understand why you need to use multiple shadow roots/DOM in your app? In general, using shadow roots in an application (vs a reusable component) is not necessary or even recommended, as that indeed complicates global styling (aka theme) without benefit.
The purpose of shadom DOM is precisely to prevent global styles from affecting the internals. If you want the same styles to be applied to a certain part of the DOM, then place that DOM in the parent (or light DOM) or import the same stylesheet within the shadow DOM (to make that style dependency explicit).
We are building an application with lit web components that are composed of Vaadin components. So, yes, we are using shadow dom etc. where Vaadin components will be nested within the shadow DOM. I don’t see why this would be bad design as this is the way it is done with web components (and also in the Vaadin implementation…)
So I understand 99% of the users is using a platform. But for the 1% users it would be good indicate how this can be done and what is best practice.
Do I understand correctly when we’re:
not using a framework (like Hilla etc.)
implement an application by using lit web components (so with shadow DOM)
the best (and only?) way to achieve global Vaadin theming is to use the registerStyles concept?
But I would strongly recommend not to use shadow roots all over your UI, as it will make any styling difficult, as the same scoping applies to all css, not just for Vaadin components. (We initially used that approach for the Hilla framework, but quickly ditched it specifically for that reason.)
As for “why not, since components use it?” the answer is that while components are self-contained atomic elements, similar to native html elements, the rest of your UI is not: it’s a bunch of non-atomic compositions of html, web components, etc. Components benefit from style encapsulation as it prevents css from the rest of the page (e.g. from 3rd party libraries) from inadvertently affecting them. Another benefit is similar encapsulation of the javascript in them. Your UI in general hardly benefits from that encapsulation, and it instead becomes a burden.
You can still use Lit and LitElement to build your views, but you should override the createRenderRoot() method and instead of creating a shadow root, return the host element directly, so that Lit renders the component template into the light DOM of the host.
You lose the ability to use slots, but if you need those, then that implies that you might be missing a reusable component instead, and should reevaluate the composition of your view.
I think what were effectively saying, is that registerStyles() is the only option at the moment (and not recommended), and we aren’t planning on introducing other ways of injecting styles to our components across shadow DOM boundaries.