Skip to content

Theming system renewal #7453

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

Open
3 of 20 tasks
rolfsmeds opened this issue Mar 19, 2025 · 6 comments
Open
3 of 20 tasks

Theming system renewal #7453

rolfsmeds opened this issue Mar 19, 2025 · 6 comments
Assignees
Labels
DS Design System feature (e.g. component) PRD v25

Comments

@rolfsmeds
Copy link
Collaborator

rolfsmeds commented Mar 19, 2025

Description

A simplification of the theme/styling system in Vaadin, to bring it closer to normal/native web development, and minimize Vaadin-specific peculiarities, while keeping migration from earlier versions as painless as possible.

Tier

Free

License

Apache 2.0

Motivation

Background

Mainly due to shadow DOM styling in Vaadin components, Vaadin themes have traditionally needed to be more than just stylesheets. This has required various Vaadin-specific concepts and APIs that new users have had to learn, regardless of their prior knowledge of web development and CSS.

Problem

With the introduction of 100% light-DOM styling in V24, and developments in web standards, those Vaadin-specific features are no longer necessary, but are still retained, and in some cases required, in V24, keeping the learning threshold for new users higher then necessary, and imposing certain limitations on and complications on styling Vaadin applications.

Solution

The entire "theme" concept, with its various APIs, folder structures, and special files, is retired in favor of "just normal stylesheets":

  • The special frontend/themes folder, and the components sub-folder for css shadow-DOM injection, is deprecated (but still supported).

    • Instead, stylesheets can be placed anywhere in the frontend folder.
    • As in earlier versions, stylesheets can import other stylesheets through native css @import rules.
  • The @Theme annotation is deprecated (but still supported);

    • Instead, one or more stylesheets are loaded through an annotation in Flow (e.g. @CssImport("styles.css")) and mechanisms native to HTML, CSS and React (e.g. @import url("morestyles.css") in CSS).
    • Developers can choose to apply their own CSS on top of Lumo, the new Aura styles, or neither, by importing (or omitting) the corresponding stylesheet (e.g. @import("@vaadin/lumo-styles/lumo.css"))
    • The Light and Dark Lumo variants (and corresponding variants of Aura) can be applied with a single line of CSS (color-scheme: dark), either statically, or based on the user's system settings.
  • The theme.json configuration file is deprecated (but still supported, with the exception of the lumoImports property).

    • Instead of selecting included Lumo modules with the lumoImports property in theme.json, all Lumo styles can be loaded by importing a single stylesheet (e.g. @import url("@vaadin/lumo-styles/lumo.css")).
    • Subsets of Lumo and Aura can be loaded via other sub-stylesheets if needed (e.g. @import url("@vaadin/lumo-styles/colors.css") or @import url("@vaadin/lumo-styles/components/vaadin-button.css")).
    • Instead of the cssImport and assets properties in theme.json, stylesheets and other frontend assets can be used in stylesheets using the same syntax as seen above.
    • Instead of the parent property in theme.json, parent themes can simply be loaded as normal stylesheets.
  • The themeFor parameter of the @CssImport annotation (for shadow-DOM injection) is deprecated (but still supported);

    • Already as of V24, component styling can be done entirely with normal "light DOM" CSS.
  • The special document.css file (for loading styles into the document root in embedded components) is removed as no longer necessary;

    • Instead, WebComponentExporter automatically copies any @font-face declarations in embedded stylesheets into the document root. (No other use cases for document.css are needed in modern browsers.)

Example of applying your own CSS on top of Lumo in V25 Flow:

Your Flow application class:

// Loads the stylesheet frontend/my-styles.css
@CssImport("my-styles.css");

The my-styles.css stylesheet:

@import("@vaadin/lumo-styles/lumo.css");

vaadin-button {
  background: #ccc;
}

Notes

  • This removes the need for theme-specific JS modules, which means that Hilla apps can simply load the npm package for a component instead of the theme-specific module in it.
  • The Material theme is no longer supported. No replacement is currently planned.
  • Lumo component styles will still be based on shadow-DOM CSS injection in order to avoid breaking changes to existing applications, but they will be loaded like normal stylesheets.
  • The shadow-DOM injection mechanisms in the components folder can still be used by toggling a feature flag and using the legacy @Theme annotation and themes folder structure to load a theme the legacy way.

Requirements

  • Shadow-DOM CSS injection based on media query (e.g. @media vaadin-button {...} to load styles into the shadow DOM of vaadin-button).
  • Support for loading bundled CSS from an npm package with @CssImport.
  • Lumo refactored
    • to normal CSS stylesheets.
    • to use the @media to inject component shadow DOM styles.
    • to support light/dark variants through color-scheme CSS property.
    • to be based on the new base component styles
  • Flow API for loading frontend assets (like stylesheets, images, etc) from npm packages (e.g. through additional parameters for the @NpmPackage annotation).
  • Feature flag for enabling shadow DOM CSS injection through the components theme sub-folder.
  • WebComponentExporter automatically copies @font-face declarations into document root.
  • Custom themes can be packaged into a JAR to be loaded into an application before its own styles.
  • @Theme, themeFor and include parameter deprecated.
  • Documentation

Nice-to-haves

  • Support for loading assets from npm packages with the CSS url() syntax, for stylesheets and other assets used via CSS. (Otherwise stylesheets from NPM packages, including Lumo and Aura, will need to be done with @CssImport etc.

Risks, limitations and breaking changes

Risks

Nothing specific expected at this point.

Limitations

Material theme will no longer be supported.

Breaking changes

These changes are not expected to be breaking for most Vaadin applications. Below are some cases where small adjustments will be needed:

  • Applications without a @Theme annotation must explicitly load Lumo styles (e.g. by adding a single @CssImport("@vaadin/lumo/lumo.css") annotation).
  • Applications using the Material theme will need to stay on V24, refactor their styling to be based on Lumo or Aura, or build their own Material theme.

Materials

RFC

See PRDs for

Metrics

TBD

Pre-implementation checklist

  • Estimated (estimate entered into Estimate custom field)
  • Product Manager sign-off
  • Engineering Manager sign-off

Pre-release checklist

  • Documented (link to documentation provided in sub-issue or comment)
  • UX/DX tests conducted and blockers addressed
  • Approved for release by Product Manager

Security review

None

@rolfsmeds rolfsmeds added the PRD label Mar 19, 2025
@github-project-automation github-project-automation bot moved this to Under consideration in Roadmap Mar 19, 2025
@rolfsmeds rolfsmeds moved this from Under consideration to December 2025 (25.0) in Roadmap Mar 19, 2025
@rolfsmeds rolfsmeds marked this as a duplicate of #7350 Mar 19, 2025
@rolfsmeds rolfsmeds added DS Design System feature (e.g. component) v25 labels Mar 19, 2025
@knoobie
Copy link
Contributor

knoobie commented Mar 20, 2025

Instead of selecting included Lumo modules with the lumoImports property in theme.json, all Lumo styles can be loaded by importing a single stylesheet (e.g. @import url("@vaadin/lumo-styles/lumo.css")).

Is there a split between free/pro/prime components? Or is everything included in lumo.css?

@jouni
Copy link
Member

jouni commented Mar 20, 2025

Good question, @knoobie. We’ve assumed all components would be included, as we expect most of the styling to reside in the component JS modules themselves, and themes are mostly a layer on top that sets custom properties and minimal component-specific selectors (this will probably vary between components).

Are you mainly worried about the unnecessary CSS that gets imported for the components you’re not using? Or do you have some other concerns?

@knoobie
Copy link
Contributor

knoobie commented Mar 20, 2025

Are you mainly worried about the unnecessary CSS that gets imported for the components you’re not using? Or do you have some other concerns?

Possible things that come into mind that might be a problem:

  • unnecessary CSS that gets imported
  • I don't know how you want to include css of components into lumo.. with urls? what happens if those aren't available? e.g. excluded? is vite intelligent enough to filter those or could this result in 404 at runtime?
  • could there be a license problem? Lumo CSS includes CSS of components with another license?

e.g. lumo.styles looks like this:

@import("@vaadin/pro-component/lumo.css");
@import("@vaadin/free-component1/lumo.css");
@import("@vaadin/free-component2/lumo.css");
@import("@vaadin/free-component3/lumo.css");

@jouni
Copy link
Member

jouni commented Mar 20, 2025

All Lumo-related stylesheets are going to be in the same package (e.g. @vaadin/vaadin-lumo-styles), instead of in the component packages like today.

I suppose the license wouldn't be an issue because of that, since the Lumo theme package is non-commercial.

If you worry about unused CSS, you can import only the parts of Lumo you actually need, instead of the catch-all lumo.css stylesheet. That’s the idea, at least.

@rolfsmeds
Copy link
Collaborator Author

We could have a separate sub-catch-all stylesheet that only includes free component stylesheets, if it looks like it might be an issue.

@rolfsmeds rolfsmeds mentioned this issue Mar 20, 2025
14 tasks
@rolfsmeds rolfsmeds self-assigned this Mar 20, 2025
@vursen
Copy link

vursen commented Apr 9, 2025

The themeFor parameter of the @CssImport annotation (for shadow-DOM injection) is deprecated (but still supported)

Instead, WebComponentExporter automatically copies any @font-face declarations in embedded stylesheets into the document root

This is what @CssImport does in embedded web components right now:

  1. @CssImport("my-component.css") adds the stylesheet to both the regular DOM and the Shadow DOM of all WebComponentExporter classes regardless if they use the annotated class anywhere.
  2. @CssImport(value = "my-component.css", themeFor = "my-theme") adds the stylesheet only to the Shadow DOM of WebComponentExporter classes that have @Theme("my-theme") annotation.

After deprecating @Theme and themeFor, @CssImport("my-component.css") will become the only option left for adding stylesheets to embedded web components. However, @CssImport without themeFor does not provide the same level of style encapsulation, which makes it an unsuitable replacement for themeFor in its current form.

Here are the options I have in mind to address that:

  1. Modify the behavior of @CssImport("my-component.css") so that the stylesheet is added only to WebComponentExporter classes that include the CssImport-annotated class in their component hierarchy.
  2. Add a new option to @CssImport to explicitly specify WebComponentExporter classes that it should apply to, something like:
// global.css will be added to the regular DOM and the shadow DOM of all exporters
@CssImport("global.css")
public class MyComponent extends Div {}
// my-component.css will be added only to the Shadow DOM of the specified exporters,
// @font-face definitions will be extracted to the regular DOM
@CssImport(value = "my-component.css", exporters = { ChatExporter.class, LoginFormExporter.class }) 
public class MyComponent extends Div {}

Update: It turns out themeFor doesn't work with embedded web components at all because they don't extend ThemableMixin.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
DS Design System feature (e.g. component) PRD v25
Projects
Status: December 2025 (25.0)
Development

No branches or pull requests

4 participants