From vaadin-development
Guide Claude on Vaadin 25 theming with both Aura and Lumo themes. This skill should be used when the user asks to "choose a theme", "set up Aura", "set up Lumo", "customize the theme", "change colors", "enable dark mode", "customize design tokens", "use theme variants", "use utility classes", "change the color scheme", or needs help with theme-specific CSS custom properties, component theme variants, or building a custom theme in Vaadin 25.
npx claudepluginhub marcushellberg/vaadin-development-plugin --plugin vaadin-developmentThis skill uses the workspace's default tool permissions.
Use the Vaadin MCP tools (`search_vaadin_docs`, `get_component_styling`, `get_component_java_api`) to look up the latest documentation whenever uncertain about a specific API detail. Always set `vaadin_version` to `"25"` and `ui_language` to `"java"`.
Builds scalable Tailwind CSS design systems using design tokens, component variants, responsive patterns, and accessibility. Use for component libraries, theming, UI standardization, and dark mode setup.
Builds UIs with Tailwind CSS v4 and shadcn/ui using CSS-first config, OKLCH colors, CVA variants, semantic tokens, responsive design, dark mode, and Radix/Base UI primitives.
Guides DaisyUI v5 best practices, shadcn/ui to DaisyUI migration mappings, oklch theme configuration, color transitions, and component catalog for class-based Tailwind UIs.
Share bugs, ideas, or general feedback.
Use the Vaadin MCP tools (search_vaadin_docs, get_component_styling, get_component_java_api) to look up the latest documentation whenever uncertain about a specific API detail. Always set vaadin_version to "25" and ui_language to "java".
Vaadin 25 ships two fully supported themes — Aura and Lumo. They differ in visual style, customization approach, and available features. This skill covers both.
| Factor | Aura | Lumo |
|---|---|---|
| Visual style | Modern, uses transparencies and gradients | Classic, clean and flat |
| Customization model | Few core properties, computed variations | Many individual tokens, granular control |
| Color system | 7-color palette, auto-computed variants | Semantic color scales with explicit opacity variants |
| Font sizing | Single --aura-base-font-size, computed scale | Individual --lumo-font-size-* tokens |
| Spacing/sizing | Single --aura-base-size, computed gaps/padding | Individual --lumo-space-* tokens |
| Border radius | Single --aura-base-radius, computed | Individual --lumo-border-radius-* tokens |
| Utility classes | None | LumoUtility.* (Tailwind-like) |
| Dark mode | color-scheme: light dark (CSS native) | [theme~="dark"] selector |
| Elevation | Surface level system (--aura-surface-level) | Explicit shadow tokens (--lumo-box-shadow-*) |
Choose Aura when you want a modern look with minimal configuration — change a few core properties and the entire app adapts. Good for rapid prototyping and apps where broad visual consistency matters more than pixel-level control.
Choose Lumo when you need fine-grained control over individual design tokens, want to use utility classes from Java, or need the compact/dense theme preset. Good for data-heavy enterprise apps and when you want Tailwind-like styling from Java.
Pick one theme and stick with it. Mixing theme tokens (e.g., --aura-* properties with Lumo, or LumoUtility classes with Aura) produces broken or unpredictable results.
Themes are loaded via @StyleSheet on your AppShellConfigurator class. The theme stylesheet must be loaded before any other stylesheets.
Aura:
@StyleSheet(Aura.STYLESHEET)
@StyleSheet("styles.css")
public class Application implements AppShellConfigurator {
}
Lumo:
@StyleSheet(Lumo.STYLESHEET)
@StyleSheet("styles.css")
public class Application implements AppShellConfigurator {
}
Lumo with utility classes:
@StyleSheet(Lumo.STYLESHEET)
@StyleSheet(Lumo.UTILITY_STYLESHEET)
@StyleSheet("styles.css")
public class Application implements AppShellConfigurator {
}
There is no utility class stylesheet for Aura. Lumo.UTILITY_STYLESHEET only works with the Lumo theme.
Aura has a 7-color palette: neutral, red, orange, yellow, green, blue, purple. Each is a single value from which text, border, and surface variants are computed automatically.
html {
/* Override palette colors */
--aura-neutral: #6b7280;
--aura-red: #ef4444;
--aura-green: #22c55e;
--aura-blue: #3b82f6;
--aura-purple: #8b5cf6;
--aura-orange: #f97316;
--aura-yellow: #eab308;
}
Accent color — the primary action color. Applied per-component or globally:
html {
--aura-accent-color: #3b82f6; /* global accent */
}
/* Or per-component */
vaadin-button {
--aura-accent-color: #42C556;
}
Background and surface colors:
html {
--aura-background-color-light: #f8fafc;
--aura-background-color-dark: #0f172a;
}
For more variations than the palette provides, use CSS color-mix() or relative color functions.
Lumo uses semantic color scales with explicit opacity variants:
html {
/* Primary — buttons, links, active indicators */
--lumo-primary-color: hsl(220, 80%, 50%);
--lumo-primary-color-50pct: hsla(220, 80%, 50%, 0.5);
--lumo-primary-color-10pct: hsla(220, 80%, 50%, 0.1);
--lumo-primary-text-color: hsl(220, 80%, 45%);
--lumo-primary-contrast-color: #fff;
/* Semantic status colors */
--lumo-error-color: hsl(0, 75%, 55%);
--lumo-success-color: hsl(150, 60%, 40%);
--lumo-warning-color: hsl(40, 95%, 50%);
/* Surface colors */
--lumo-base-color: hsl(220, 20%, 98%);
--lumo-contrast-5pct: hsla(220, 20%, 0%, 0.05);
--lumo-contrast-10pct: hsla(220, 20%, 0%, 0.1);
}
Each semantic color (primary, error, success, warning) has *-color, *-color-50pct, *-color-10pct, *-text-color, and *-contrast-color variants. The contrast scale (--lumo-contrast-5pct through --lumo-contrast) provides 10 levels for backgrounds, borders, and text.
Both themes use the shared @ColorScheme annotation for static configuration:
@ColorScheme(ColorScheme.Value.DARK)
public class Application implements AppShellConfigurator {
}
Values: LIGHT (default), DARK, LIGHT_DARK (follows OS preference).
Aura uses the native CSS color-scheme property. The LIGHT_DARK value maps to color-scheme: light dark, which automatically follows the user's OS preference.
Aura color properties have -light and -dark suffixed variants. If you customize colors and support both schemes, override both:
html {
--aura-background-color-light: #f8fafc;
--aura-background-color-dark: #0f172a;
--aura-accent-color-light: #3b82f6;
--aura-accent-color-dark: #60a5fa;
}
Lumo uses the [theme~="dark"] selector:
[theme~="dark"] {
--lumo-base-color: hsl(220, 20%, 12%);
--lumo-primary-color: hsl(220, 85%, 65%);
--lumo-body-text-color: hsla(0, 0%, 100%, 0.9);
}
Enable dark mode programmatically:
UI.getCurrent().getElement().getThemeList().add("dark");
Aura computes a full type scale from a single base value:
html {
--aura-font-family: 'Your Font', sans-serif;
--aura-base-font-size: 16; /* unitless number, represents px */
--aura-base-line-height: 1.5; /* unitless, relative to font size */
}
This computes --aura-font-size-xs through --aura-font-size-xl and corresponding line heights automatically. Aura also supports dynamic font sizing on iOS/iPadOS.
Lumo provides individual tokens for each size:
html {
--lumo-font-family: 'Your Font', sans-serif;
--lumo-font-size-xxxl: 2rem;
--lumo-font-size-xxl: 1.5rem;
--lumo-font-size-xl: 1.25rem;
--lumo-font-size-l: 1.125rem;
--lumo-font-size-m: 1rem;
--lumo-font-size-s: 0.875rem;
--lumo-font-size-xs: 0.8125rem;
--lumo-font-size-xxs: 0.75rem;
}
@font-face {
font-family: 'Your Font';
src: url('./fonts/your-font.woff2') format('woff2');
font-display: swap;
}
html {
/* Aura */
--aura-font-family: 'Your Font', sans-serif;
/* OR Lumo */
--lumo-font-family: 'Your Font', sans-serif;
}
Aura computes spacing and sizing from core properties:
html {
--aura-base-size: 16; /* unitless, range 12–24, controls gap/padding */
--aura-base-radius: 6; /* unitless, range 0–10, controls border radius */
}
These compute the shared --vaadin-gap, --vaadin-padding, and radius properties automatically.
Lumo provides individual tokens:
html {
/* Spacing */
--lumo-space-xs: 0.25rem;
--lumo-space-s: 0.5rem;
--lumo-space-m: 1rem;
--lumo-space-l: 1.5rem;
--lumo-space-xl: 2.5rem;
/* Border radius */
--lumo-border-radius-s: 4px;
--lumo-border-radius-m: 8px;
--lumo-border-radius-l: 16px;
}
Lumo compact preset — reduces component sizing globally. Load as an additional stylesheet. Useful for data-dense views.
Lumo utility classes for spacing (Lumo only):
card.addClassNames(
LumoUtility.Padding.LARGE,
LumoUtility.Gap.MEDIUM
);
Both themes provide style variants via addThemeVariants(). The variant constants are prefixed with the theme name (AURA_ or LUMO_).
// Aura theme
button.addThemeVariants(ButtonVariant.AURA_PRIMARY);
// Lumo theme
button.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
Not all variants are available in both themes. Check the component documentation for which variants each theme supports. Common examples:
| Variant | Aura | Lumo |
|---|---|---|
| Button: primary | AURA_PRIMARY | LUMO_PRIMARY |
| Button: tertiary | AURA_TERTIARY | LUMO_TERTIARY |
| Button: tertiary-inline | — | LUMO_TERTIARY_INLINE |
| Button: small/large | — | LUMO_SMALL / LUMO_LARGE |
| Button: icon | — | LUMO_ICON |
| Button: success | AURA_SUCCESS | LUMO_SUCCESS |
| Button: error | AURA_ERROR | LUMO_ERROR |
| Button: warning | AURA_WARNING | LUMO_WARNING |
| Button: contrast | — | LUMO_CONTRAST |
| Grid: no border | AURA_NO_BORDER | LUMO_NO_BORDER |
| Grid: compact | AURA_COMPACT | LUMO_COMPACT |
| Grid: no row borders | AURA_NO_ROW_BORDERS | LUMO_NO_ROW_BORDERS |
| Grid: column borders | AURA_COLUMN_BORDERS | LUMO_COLUMN_BORDERS |
| TextField: small | — | LUMO_SMALL |
Aura accent colors for buttons — Aura uses CSS classes instead of theme attributes for certain color variants:
/* These classes are applied automatically by AURA_SUCCESS, AURA_ERROR, AURA_WARNING */
vaadin-button.aura-accent-green { /* success */ }
vaadin-button.aura-accent-red { /* error */ }
vaadin-button.aura-accent-yellow { /* warning */ }
LumoUtility.* provides Tailwind-like utility classes for layout, spacing, colors, typography, borders, shadows, and more. They require the Lumo theme and Lumo.UTILITY_STYLESHEET.
card.addClassNames(
LumoUtility.Background.BASE,
LumoUtility.BorderRadius.MEDIUM,
LumoUtility.BoxShadow.SMALL,
LumoUtility.Padding.LARGE,
LumoUtility.Display.FLEX,
LumoUtility.FlexDirection.COLUMN,
LumoUtility.Gap.SMALL
);
Categories: Background, Border, BorderColor, BorderRadius, BoxShadow, Display, FlexDirection, FlexGrow, FlexShrink, FlexWrap, FontSize, FontWeight, Gap, Height, JustifyContent, Margin, Overflow, Padding, Position, TextAlignment, TextColor, Width, and responsive breakpoint variants.
Aura has no equivalent. If using Aura, use CSS custom properties, inline styles, or custom CSS classes instead.
Aura uses a surface color system where elevation is controlled by --aura-surface-level. Higher levels are lighter in light mode (closer to white) and lighter in dark mode (closer to the user).
.card {
background: var(--aura-surface-color);
--aura-surface-level: 2; /* default is 1 */
--aura-surface-opacity: 0.5; /* transparency, default 0.5 */
}
The surface color is computed from --aura-background-color, the level, and the opacity. Nesting elements with the same surface color creates a stacking effect due to transparency.
Lumo provides individual shadow tokens:
html {
--lumo-box-shadow-xs: 0 1px 2px 0 rgba(0,0,0,0.05);
--lumo-box-shadow-s: 0 2px 4px -1px rgba(0,0,0,0.1);
--lumo-box-shadow-m: 0 4px 8px -2px rgba(0,0,0,0.1);
--lumo-box-shadow-l: 0 8px 16px -4px rgba(0,0,0,0.15);
--lumo-box-shadow-xl: 0 16px 32px -8px rgba(0,0,0,0.2);
}
Apply from Java with utility classes (Lumo only):
card.addClassNames(LumoUtility.BoxShadow.SMALL);
Both themes support shared --vaadin-* component style properties that work regardless of theme:
/* Shared properties — work with any theme */
vaadin-horizontal-layout {
--vaadin-horizontal-layout-gap: 16px;
}
vaadin-text-field::part(input-field) {
border-radius: 8px;
}
For theme-specific styling, use ::part() selectors with the appropriate theme tokens:
/* Lumo */
vaadin-grid::part(header-cell) {
background-color: var(--lumo-contrast-5pct);
}
/* Aura — adjust surface level instead */
vaadin-grid::part(header-cell) {
--aura-surface-level: 0;
}
Create a reusable theme CSS file that overrides the core properties of your chosen theme:
Aura custom theme:
/* styles/my-theme.css */
html {
--aura-font-family: 'Inter', sans-serif;
--aura-base-font-size: 15;
--aura-base-size: 16;
--aura-base-radius: 8;
--aura-accent-color-light: #2563eb;
--aura-accent-color-dark: #60a5fa;
--aura-background-color-light: #f8fafc;
--aura-background-color-dark: #0f172a;
}
Lumo custom theme:
/* styles/my-theme.css */
html {
--lumo-font-family: 'Inter', sans-serif;
--lumo-primary-color: hsl(220, 80%, 50%);
--lumo-primary-color-50pct: hsla(220, 80%, 50%, 0.5);
--lumo-primary-color-10pct: hsla(220, 80%, 50%, 0.1);
--lumo-primary-text-color: hsl(220, 80%, 45%);
--lumo-border-radius-m: 8px;
--lumo-border-radius-l: 16px;
}
[theme~="dark"] {
--lumo-primary-color: hsl(220, 85%, 65%);
--lumo-base-color: hsl(220, 20%, 12%);
}
Load with @StyleSheet:
@StyleSheet(Aura.STYLESHEET) // or Lumo.STYLESHEET
@StyleSheet("styles/my-theme.css")
@StyleSheet("styles.css")
public class Application implements AppShellConfigurator {
}
var(--lumo-space-m) not 1rem, or adjust --aura-base-size instead of hardcoding pixel values.ButtonVariant, GridVariant, etc. offer before writing custom styles.@StyleSheet for the theme must come before application stylesheets.::part() for component internals — Vaadin components use shadow DOM; ::part() selectors are the supported way to style internal parts.--aura-* properties in a Lumo app or --lumo-* in an Aura app. These properties don't exist in the other theme and will have no effect.LumoUtility with Aura — utility classes only work with the Lumo theme. With Aura, use custom CSS classes or inline styles.color-scheme with -light/-dark suffixed properties; Lumo uses [theme~="dark"]. Don't use Lumo's dark selector with Aura or vice versa.@CssImport — this annotation is removed in Vaadin 25. Use @StyleSheet instead.@StyleSheet ordering.For complete token tables, variant comparison charts, and theme setup recipes, see references/theming-patterns.md. For component ::part() selectors and CSS animation recipes, see the frontend-design skill's references/design-patterns.md.