Creating a Custom Theme
- Theme Folder Structure
- Applying a Custom Theme
- Master Style Sheet
- Vaadin Component Styles
- Other Theme Assets
- Document Root Style Sheet
- Style Loading Order
- Limitations
A custom theme is the easiest way to provide a custom look and feel for your entire application. It can be packaged as a dependency for reuse in multiple applications, as described in Packaging a Theme for Reuse. The CSS in a custom theme is always applied on top of the default Lumo theme.
Note
| Custom theme feature is only for NPM mode and will not be applied for compatibility mode. Compatibility Mode is no longer supported from Vaadin 14.12 onwards. |
Theme Folder Structure
For use in a single application, a custom theme is implemented as a folder inside frontend/themes, with the following minimal structure:
frontend
└── themes (1)
└── my-theme (2)
├── components/ (3)
└── styles.css (4)
-
The
themes
folder can contain multiple custom themes (but only one can be applied to the application at a time). -
Each theme is in its own sub-folder. The name of this folder is provided as a parameter to the
@Theme
annotation to apply the theme to the application. -
The
components
sub-folder is for component style sheets that target the (local CSS) internals of Vaadin components. -
styles.css
is the theme’s master style sheet that is automatically loaded when the theme is applied.
See Style Scopes for details on global vs local CSS.
Applying a Custom Theme
You can apply a different theme using the @Theme
annotation on the root navigation class or the router layout defined in the @Route
annotation.
An application may only have one such class and you need to define any similar configuration annotations in the same class, such as @PWA
or PageTitle
.
For example, in a Spring Boot application, you could have an application configuration class such as the following:
@Route("")
@Theme(themeFolder = "my-theme")
public class LumoApplication extends Div {
...
}
Changes to the theme folder’s contents are automatically picked up during development. If the application has live reload enabled, the UI should reload automatically. Otherwise a page reload may be needed to see the changes.
Sometimes, compilation throws an error (“no such file or directory”) when files or folders are removed from the theme folder while the application is running. This might happen due to the following reasons:
-
The file being removed is a style sheet referenced from
my-theme/styles.css
, or from other style sheet in the theme folder. In that case, to avoid re-compilation errors, remove the style sheet import first, and then remove the file. -
The file being removed is a component style sheet in the
my-theme/components
folder, or the wholemy-theme/components
folder. The files inside the components folder are referenced from an autogenerated file, such asmy-theme.generated.js
, and re-compilation fails because webpack cannot find them. To avoid errors, remove your component style sheet simultaneously (in one go) with the theme-generated file.
Note
|
Dismissing the error message
When you encounter a “no such file or directory” error reported by webpack, shown in an overlay in your application, click on the overlay (or refresh the browser page), and it should disappear.
You can then continue working on your application and theming.
If it doesn’t help, you need to restart the application.
|
Master Style Sheet
When a custom theme is applied to the application, the master style sheet styles.css
is loaded automatically as global CSS.
Other style sheets, except for Vaadin component styles in the components folder, need to be included through the master style sheet using CSS @import
statements.
The master style sheet typically contains:
-
Imports of other global style sheets within the theme folder.
-
Overrides of default Lumo properties and declarations of custom CSS properties.
-
Styles applied to UI elements through class names and other CSS selectors.
@import other-styles.css (1)
html, :host { (2)
--lumo-border-radius: 0.5em;
--my-brand-color: purple;
}
.application-header { (3)
background: white;
border-bottom: 1px solid gray;
}
CSS custom properties (for example, for overriding Lumo defaults) are recommended to use the selector “html,:host
“, as in the example above, to ensure that they are applied when the theme is applied to an embedded Flow application or component.
Note
|
Restriction on
At the moment all @import statements@import statements need to be in the theme root folder.
See Vaadin Flow issue 9794.
|
Vaadin Component Styles
As the internal styling of Vaadin components is isolated from the global CSS inside the component’s shadow DOM, the easiest way to customize their styles is through the CSS properties available in the built-in themes (see Foundation section for details), and by injecting custom CSS directly into the shadow DOM of the components by placing them in the components sub-folder.
To inject CSS into the shadow DOM of a Vaadin component, create a style sheet whose name matches the web component HTML element name of the component in the components sub-folder.
As an example, to apply styling to the vaadin-button
component, create a style sheet called vaadin-button.css
.
frontend
└── themes
└── my-theme
├── components
│ ├── vaadin-button.css
│ └── vaadin-text-field.css
└── styles.css
See Styling Components for details on writing CSS for Vaadin components.
This style injection is based on a feature used by Vaadin components called Themable Mixin. You can create your own web components that use the same feature to make them support this theming mechanism.
Components that do not use shadow DOM, such as custom Flow-based components, can be styled using regular global CSS placed in styles.css
or any other style sheet imported through it.
Other Theme Assets
In addition to style sheets, themes often need other assets like fonts, images, and icons. These can be included in the theme folder, either in the root or in sub-folders as desired.
In the following example, a couple of images are included in an img
sub-folder (1), and a font file is included in the theme root (2).
frontend
└── themes
└── my-theme
├── components/
├── img (1)
│ ├── logo.png
│ └── background.jpg
├── my-font.woff (2)
└── styles.css
These assets can be used in the theme’s style sheets through URIs relative to the style sheet’s location:
@font-face {
font-family: "My Font";
src: url('./my-font.woff') format("woff");
}
.application-logo {
background-image: url('./img/logo.png');
}
Document Root Style Sheet
To ensure that certain styles are always applied to the document root rather than the shadow root of an embedded Flow application or component, they can be placed in a special style sheet in the theme folder root called document.css
.
This is mainly needed for @font-face
declarations that are not supported inside web component shadow DOM, and only when the theme is going to be used with embedded Flow applications or components inside another application.
Another example is when the theme should be applied to an embedded Flow application or component which is shown in an overlay inside another application.
Since the overlay cannot access the styles from web component shadow DOM, the styles must also be added to the document.css
.
To avoid copy-pasting such styles in two places, move them into a separate style sheet and use @import
to include them in both styles.css
and document.css
.
Style Loading Order
When using a custom theme, CSS is loaded in a Vaadin application in the following order:
-
Lumo styles
-
Custom theme styles
-
Manually loaded additional style sheets (for example, using
@CssImport
in Flow)
Limitations
The following limitations apply to custom themes:
-
The theme cannot be switched run-time.
-
Using the built-in Material theme is not currently supported. Custom themes are always loaded on top of the Lumo theme.
-
At the moment all @import statements need to be in style sheets in the theme root folder.
F484F31E-4459-40A5-978C-E1DBAE7779BD