Creating a Custom Theme Class

Creating custom theme classes is not recommended after 14.6 after which the recommendation is to use the new Custom Theme feature.

If customizing built-in themes is not enough and you want complete control, you can create a completely custom theme from scratch. This means that you explicitly define the style sheets for all the components that are used in your application.

Prerequisites

This documentation applies only to server-side (Java) applications.

This approach is recommended when you want to have full control over the CSS that gets sent to the browser, if you want to avoid sending unnecessary CSS to the client.

Before creating a custom theme, you should consider customizing one of the built-in themes instead and see if that satisfies your requirements. See the other articles in this section for instructions how to do that.

Create Theme Class

You can integrate a custom component theme to be used with the built-in Vaadin components. To do this, you need to create a Theme class that tells Vaadin how to translate the base un-themed component imports into your themed version.

The most important methods are:

  • getBaseUrl(): This should return the import base path that is used to determine if it is an import that can be changed into a theme import. For Vaadin components that is /src/.

  • getThemeUrl(): This should return what the base URL part should be changed into to get the correct theme import. For Vaadin components that is /theme/[themeName].

For example, overriding getBaseUrl() and getThemeUrl() in the MyTheme class would go as follows:

@JsModule("@vaadin/vaadin-lumo-styles/color.js")
public class MyTheme implements AbstractTheme {
    @Override
    public String getBaseUrl() {
        return "/src/";
    }

    @Override
    public String getThemeUrl() {
        return "/theme/myTheme/";
    }
}

If you need more control, you can use the getHeaderInlineContents() method. It returns a collection of HTML that will be inlined to the BootstrapPage body.

Implement getHeaderInlineContents() to add a custom style that includes the correct typography styles:

@Override
public List<String> getHeaderInlineContents() {
    return Collections.singletonList("<custom-style>\n"
            + "<style include=\"lumo-color lumo-typography\">"
            + "</style>\n"
            + "</custom-style>");
}

Your can also support theme variants. The Lumo theme, for example, supports both light and dark variants.

Override getHtmlAttributes() in your custom theme class to add support for variants.

For example, override getHtmlAttributes() as follows:

@Override
public Map<String, String> getHtmlAttributes(
        String variant) {
    if ("dark".equals(variant)) {
        // The <body> element will have the "theme"
        // attribute set to "dark" when the dark variant
        // is used
        return Collections.singletonMap("theme", "dark");
    }
    return Collections.emptyMap();
}

Create Style Sheets

You need to provide a style sheet for each component used in your application. Omitted components display without any styles. This is because all Vaadin components are imported using the /src/ path, and it is the responsibility of the theme class to replace the getBaseUrl() pattern with an appropriate path to the themed elements (as returned in the getThemeUrl()).

Create style sheets as JavaScript modules (.js files) for each of the Vaadin elements in the /frontend/theme/myTheme/ folder.

For example, modify the vaadin-button component by adding custom rules to the original Lumo rules in frontend/theme/myTheme/vaadin-button.js:

// Import the non-themed component
import '@vaadin/vaadin-button/src/vaadin-button.js';

// Optional: reuse Lumo styles for button
import '@vaadin/vaadin-button/theme/lumo/vaadin-button-styles.js';

import { registerStyles, css } from '@vaadin/vaadin-themable-mixin/register-styles.js';

// Register your custom CSS rules for vaadin-button
registerStyles('vaadin-button', css`
    :host {
      border-radius: 0;
    }
`);