Styling: Lumo and CSS
Vaadin components already look neat — that is the work of Lumo, the standard Vaadin theme. You can change the look on three levels: ready-made component variants from Java, Lumo utility CSS classes and your own CSS file. Start with the first one — it needs no CSS at all.
Loading styles
All stylesheets are loaded with @StyleSheet annotations on the main class:
// src/main/java/com/example/blog/Application.java
package com.example.blog;
import com.vaadin.flow.component.dependency.StyleSheet;
import com.vaadin.flow.component.page.AppShellConfigurator;
import com.vaadin.flow.component.page.ColorScheme;
import com.vaadin.flow.theme.lumo.Lumo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@StyleSheet(Lumo.STYLESHEET)
@StyleSheet(Lumo.UTILITY_STYLESHEET)
@StyleSheet("styles.css")
@ColorScheme(ColorScheme.Value.LIGHT_DARK)
public class Application implements AppShellConfigurator {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}| Annotation | What it loads |
|---|---|
@StyleSheet(Lumo.STYLESHEET) | The Lumo theme |
@StyleSheet(Lumo.UTILITY_STYLESHEET) | Lumo utility classes |
@StyleSheet("styles.css") | Your file src/main/resources/META-INF/resources/styles.css |
@ColorScheme(LIGHT_DARK) | Light or dark theme, following the system settings |
Turn on dark mode in your system and reload the page: the background turns dark and the text light.
Component variants
Variants are ready-made styles you turn on from Java:
// src/main/java/com/example/blog/views/PostListView.java (part of the constructor)
add.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
grid.addThemeVariants(GridVariant.LUMO_ROW_STRIPES);The "New post" button is blue, and grid rows alternate in color. Similar variants exist for fields (TextFieldVariant.LUMO_SMALL), notifications (NotificationVariant.LUMO_ERROR) and other components.
Utility classes
LumoUtility is a set of constants with CSS classes for spacing, font sizes and colors:
// src/main/java/com/example/blog/views/MainLayout.java (part of the constructor)
H1 title = new H1("Blog admin");
title.addClassNames(LumoUtility.FontSize.LARGE, LumoUtility.Margin.NONE, LumoUtility.Flex.GROW);The header title gets smaller, loses its margins and stretches, pushing the next header items to the right. Import: com.vaadin.flow.theme.lumo.LumoUtility.
Your own CSS
Give a component a class with addClassName and describe it in styles.css:
/* src/main/resources/META-INF/resources/styles.css */
.post-list {
max-width: 960px;
margin: 0 auto;
}
vaadin-grid::part(post-title) {
font-weight: 600;
}
vaadin-grid::part(draft) {
color: var(--lumo-error-text-color);
}The list view with addClassName("post-list") is at most 960 pixels wide and centered. The two other rules style grid cells — Java gives the cells their names:
// src/main/java/com/example/blog/views/PostListView.java (part of the constructor)
grid.addColumn(Post::getTitle).setHeader("Title").setSortProperty("title")
.setPartNameGenerator(post -> "post-title");
grid.addColumn(post -> post.isPublished() ? "Published" : "Draft").setHeader("Status")
.setPartNameGenerator(post -> post.isPublished() ? null : "draft");Post titles in the grid are bold, and the "Draft" status is red.
Common mistake
The stylesheet is in the wrong place, for example src/main/resources/styles.css. There is no error at startup, but the styles do not apply, and the browser console (F12) shows:
GET http://localhost:8080/styles.css 404 (Not Found)The browser gets only files from src/main/resources/META-INF/resources/ — the path in @StyleSheet is relative to that folder. Older Vaadin 24 tutorials use another way, the @Theme annotation and the src/main/frontend/themes/ folder. Vaadin 25 recommends @StyleSheet.
Also remember that the inner parts of components are hidden in the shadow DOM: an ordinary selector does not reach them, so use ::part(...) as in the grid example.