Theme Variants

Variants are opt-in features of each theme which affect the visual presentation of components. They do not affect their behavior or functionality.

Examples of variants include light and dark modes, density presets (compact, small, large), and visual prominence (primary, tertiary, no-borders).

Themes can define global and component-specific variants. Theme variants can be used across all Style Scopes – you don’t need to define or import them individually for each style scope.

Global Variants

Global variants affect all component instances in an application. Light and dark modes are good examples of global variants.

See the documentation for Lumo Variants and Material Variants to learn more about the built-in variants.

In server-side views (Java), use the variant attribute of the @Theme annotation. See Using Themes for more information.

@Theme(value = Lumo.class, variant = Lumo.DARK)

Component Variants

Component variants affect selected component instances. Primary buttons, and small buttons and text fields are common examples of component variants. You can combine multiple variants together for a single component, for example a small primary button.

Many components have built-in variants in both the Lumo and the Material theme. See the documentation for Lumo Variants and Material Variants to learn more about the built-in variants.

Components which have built-in variants implement the HasTheme interface and have convenient Java APIs for using them. For other components, use the Element API and the setAttribute method.

// Using the high-level HasTheme API
Button button = new Button("Themed button");
button.addThemeVariants(ButtonVariant.LUMO_PRIMARY,
        ButtonVariant.LUMO_SMALL);

Button button = new Button("Themed button");
button.getThemeNames().addAll(Arrays.asList("primary", "small"));

// Using the low-level Element API
Button button = new Button("Themed button");
String themeAttributeName = "theme";
String oldValue = button.getElement().getAttribute(themeAttributeName);
String variantsToAdd = "primary small";
button.getElement().setAttribute(themeAttributeName,
        oldValue == null || oldValue.isEmpty() ?
                variantsToAdd
                : ' ' + variantsToAdd);

Sub-component Variants

Theme variants propagate to sub-components. For example, the Combo Box component internally contains the Text Field component. Setting a theme variant on a Combo Box will also be applied on the internal Text Field component.

This also means, that even though Combo Box does not have a built-in “small” variant of its own, it can still utilize the built-in “small” variant of the Text Field component. For example:

In server-side views (Java):

ComboBox comboBox = new ComboBox();
comboBox.getElement().setAttribute("theme", TextFieldVariant.LUMO_SMALL.getVariantName());

See Styling Components to learn about the hierarchy of built-in Vaadin components, so you can use variants more effectively and know which exact components you need to target in order to customize components with sub-components.

Custom Variants

Custom variants allow you to freely customize the visual appearance of components. They are defined in an additional stylesheet which you import as component styles (see Importing Style Sheets). Technically, custom variants work exactly like built-in variants.

To create a custom variant, first we need to write the styles for that variant. For example, to create a new variant for Button, the following CSS would work:

:host([theme~="my-custom-variant"]) {
  /* Set the CSS properties you want to customize */
}

To learn how to correctly target internal parts of components and how to write the correct CSS selectors, see Styling Components.

Then, you need to import the style sheet into the corresponding component’s style scope. See Importing Style Sheets to learn more.

Finally, you can use the my-custom-variant on a Button component, as shown before.