Last week we held our second Ask Me Anything. Product Owner Rolf Smeds answered your questions on theming Vaadin apps. He kicked off the session with a review of the new simplified theming system available in Vaadin 19 with a live demo on Twitch. You can watch the recording here:
- New theme folder: There’s now a default theme folder located inside the frontend folder, with a file named
style.css. You can use this file to apply global CSS to your application, and it will be automatically loaded.
- Styling components: Styling Vaadin components is now easier as well. You can maintain the same style throughout your application. Check out the video to see it in action.
- Theme configuration: You can use the
theme.jsonfile to configure your themes. It defines which modules are imported to your theme, i.e. ‘badge’. More information about this can be found in our documentation on Theme Configuration.
- Packaging themes: And finally, you can package your themes as JAR files to use in different projects, by adding it to your maven repository and as a dependency to your app.
- Color theming: This is the documentation that Rolf uses to copy the variable names to target primary colors: https://vaadin.com/docs/latest/ds/foundation/color
Do you also love the color picker?
Highlights from the AMA
After going through the live demo, our users were excited about the new theming system. We moved the lively conversation to our Discord server for a Q&A session about the new features and theming Vaadin applications in general. Here’s a sample of what our community asked.
[Hint: Our Discord is a great place to get advice from the community and help directly from the Vaadin team]
I'm the product owner of Vaadin Design System. This means I lead the team that builds components, themes, and some of the tooling etc. around those. In today's AMA you can ask me anything about theming with Vaadin, and I'll try to get you some useful answers.
[Q]How can I change the theme at runtime?
That’s a very common question and, unfortunately, you can't really switch themes per se, even with the new system, because of the way component styles are loaded.
[Q] Can I start my app with a particular theme?
As the annotation is currently the only way to set the theme, it's pretty static. However: in most cases where you want to "select a theme", you really only need to switch between different colors etc., rather than switching between completely different themes. That can be done by implementing multiple color schemes etc. in the same theme.
[Q]The use case is that I have a product and depending on the customer it can require a completely different theme.There are essentially two ways to create a multi-theme setup:
- Implement multiple "sub themes" in the same theme, by scoping them somehow (e.g. using a classname or attribute selector) and then applying the right classname or attribute to the UI.
- Dynamically load additional stylesheets that contain theme-specific styles.
In both cases you're limited to global (page-level) CSS, so you can't load e.g. different component-specific stylesheets that way (but that can be worked around e.g. with custom properties).
The Lumo light/dark theme variants are based on approach #1 above. The dark theme is really just a set of styles scoped to a
[theme="dark"] block, and when you apply the dark theme using the old
@Theme(value=Lumo.class, variant=Lumo.DARK) annotation, it's really just adding the
theme="dark" attribute to the page root:
[Q] I'm wondering if I can create multiple themes within the frontend folder - are all themes copied / compiled to be included inside my final jar or only the theme that is used within my
Yes, you can have multiple themes in the same JAR, and then apply one of them in the application using that JAR.
[Q] How reusable is the theme in a non-Java application? Say, a React application with Vaadin components.
It's not, it relies on features in the Flow and Fusion frameworks.
[Q] Is it possible to have Vaadin apps automatically use the dark mode that users set up on the browser?
Yes. The OS dark mode is targeted using a media query
@media (prefers-color-scheme: dark), so by scoping your own styles using that, you can target it that way. My colleague Alejandro Duarte has written a piece on how to detect and apply the Lumo dark mode based on it: https://dzone.com/articles/switching-between-light-and-dark-themes-automatica
Here is a solution how to apply light or dark depending on user OS settings: https://gist.github.com/emarc/690eb2659c8b51cb895716914d65ec19
[Q] Is there only one variant allowed?
Nope. Your own theme can have as many variants as you like, you just need to decide on the selector used to differentiate between themes. Let's say you create three sets of styles in your theme,
baz, you can use the theme attribute to separate them:
and then apply the desired variant dynamically with
An extra note from Rolf:
I forgot to mention this in the stream, but there is also a way to apply the Lumo dark variant with the new theming system, as you can't combine theme folder name with variant. So to apply
Lumo.DARK, you do
This means that any variations you can do in global CSS, you can dynamically switch between.
For variations in a component's Shadow DOM CSS, it's a bit trickier, and more limited. You’re stuck with things you can do with custom properties, but you can define your own properties e.g.
--my-button-text-style that you apply to the button with
components/vaadin-button.css, and then you define a separate value for that property in each of your variants.
If you don't need to support older browsers, you should also be able to use the new
::part selector that targets elements with
part="foo" attributes from global CSS. The main reason we're not recommending this officially is that it's not supported by all browsers, and it's still a bit limiting compared to our custom approach: (https://developer.mozilla.org/en-US/docs/Web/CSS/::part)
[Q] That API feels a little bit clunky, is there any plan to integrate this into BootstrapHandler or any other once per page called listener?
Nothing tangible at this point, but I can say that this is just the first iteration of the new theme system and we intend to continue to improve it over time.
Another current limitation is that your custom theme always loads on top of Lumo, so there's no way to currently base your theme on Materia. In the future, we may provide an option (in
theme.json) to base on Material instead, or we might refactor Material theme as a variant of Lumo. In both cases you would, of course, then be able to choose which to base your own theme on.
To briefly give a bit more detail on the
::part() selector option, which can be useful especially for variants, is that instead of creating
components/vaadin-button.css in which you do
you can do this in your global styles.css:
which, since it's global CSS, can be wrapped into the
[theme="foo"] variant block.
There can still be reasons to use
@CssImport of course, e.g. you might want to use the theme only for app-wide styles, and
@CssImport to load view-specific styles separately.
[Q] Does this new theming system allow us to move all JS and CSS sources to the theme folder? Even those used via e.g.
Yes, you can put basically anything there, and then choose whether to load it using the
@Theme annotation and
styles.css, or via
Sneak peak: the Design System Publisher
Rolf gave a sneak peak of our upcoming tool called Design System Publisher. It will allow you to easily create your own documentation website based on your Design System component library/UI platform, so that you can create your own themes, custom components, set of guidelines, etc. and share them with your team to ensure you maintain a consistent style throughout all your projects.