2

I am currently in the process of migrating a Vaadin 8 application over to Vaadin 12. The look and feel should be used by the user and changed on Login or via a button press.

In Our Vaadin 8 application we had 2 themes (a dark and a light one), each with their own SASS/CSS and some shared properties. The user was able to switch it using the setTheme() Method. When a click to the switching button happened, the Look and Feel just changed. In Vaadin 12 the Theming follows a different approach and I am struggling to find a good way to implement this feature in Vaadin 12.

Let's say we don't want to create a whole new Theme and just want to use customized LUMO. I can set the Theme/Variant through the @Theme Annotation. The Downside: The Theme will be fixed at Runtime.

Also i could just write some code to apply variants to my application and components. (like in the dynamic styling chapter: https://vaadin.com/docs/flow/element-api/tutorial-dynamic-styling.html ) The Downside: It won't be very practicable to iterate through each element and apply the variant.

My question now:

What is the best way to achieve a switch between to themes at runtime? (customized light- and dark variants of Lumo or any other theme).

Would I just create 2 HTML Files (for compatibility) containing CSS and then somehow override the currently used File through a dynamic import?

I hope my question is clear and someone can point me to the right direction.

Loahrs
  • 109
  • 7
  • 1
    FYI, in Vaadin 14 with modern web browsers and four lines of JavaScript, your web app can **automatically switch** on-the-fly between Light Mode and Dark Mode to match your user’s preferences set in the host OS. See [this Answer by Marcus Hellberg](https://stackoverflow.com/a/59462815/642706) on Question, [*Vaadin Flow app switch between light and dark modes automatically*](https://stackoverflow.com/q/59462273/642706). – Basil Bourque Dec 24 '19 at 04:47
  • See also posting on Vaadin.com by Marcus Hellberg, [*Toggle dark Lumo theme variant dynamically*](https://vaadin.com/learn/tutorials/toggle-dark-theme). – Basil Bourque Dec 24 '19 at 04:50

2 Answers2

4

If you are only interested in toggling between light and dark, then you can just add/remove dark at a very high place in the DOM. E.g. the element of the UI is usually the body or at least very high up.

E.g.:

new Checkbox("Use Dark Theme").tap{
    addValueChangeListener{ cb ->
        getUI().ifPresent(){ ui ->
            def themeList = ui.getElement().getThemeList()
            if (cb.value) {
                themeList.add(Lumo.DARK)
            } else {
                themeList.remove(Lumo.DARK)
            }
        }
    }
}

edit

As asked in the comments of another answer:

To change the colors in a theme, you can override the used colors. This is the example how to change the text color for light and dark Lumo theme:

html {
    --lumo-body-text-color: red;
}
[theme~="dark"] {
    --lumo-body-text-color: yellow;
}

cfrick
  • 35,203
  • 6
  • 56
  • 68
  • Great, this is exactly what I was looking for! Thanks! Couldn't find that information from the vaadin docs, but I was sure there has to be some notation like this to make it possible without much hassle. – Loahrs Feb 05 '19 at 11:06
3

It's relatively easy to switch between two different variants of the same theme, e.g. the dark and light variants of Lumo. To do this, you only need to toggle the corresponding theme attribute on the <html> element. There's no direct access to that element from the server, but you can do it with a small snippet of JavaScript: ui.getPage().executeJavaScript("document.documentElement.setAttribute($0, $1)", "theme", "dark");

Depending on circumstances, you can or must apply the changes to the <body> element instead. In that case, you can either switch out .documentElement for .body in the JS snippet or directly use ui.getElement().setAttribute("theme", "dark") in Java.

Switching between two different base themes, e.g. Lumo vs Material is a much more complicated affair. For each component, there can only be one base theme loaded in the browser at the same time, and reloading the page is the only way of getting rid of the one that is already loaded. For each component that is used for Flow, the framework takes care of loading the right theme import in addition to the base import that doesn't have any styling. To make things even more complicated, the theme designated using @Theme is automatically included in the application's production bundle. To be able to use multiple base themes, you'd also have to somehow produce multiple different bundles and also somehow configure Flow to use the right bundle depending on circumstances.

Leif Åstrand
  • 7,820
  • 13
  • 19
  • Thank you so far. Let's say I want to customize the appearance now. If I am just using one Variant of the Theme (let's say the light version) and I want to have a different font-color or background-color, i would just create an HTML/CSS File and override it. But lets say I want to change the appearance of both Variants: Have red Font-Color in "Light" and Green Font-Color in "Dark" (just as an example). How would I manage that? Do I need two CSS Files and also switch them? Or is there a way to apply styles only when a specific variant is used? Thats the most unclear point for me. – Loahrs Feb 05 '19 at 10:37
  • To put it into one sentence: Whats the most practicable way to customize the Light and Dark Variants of Lumo? – Loahrs Feb 05 '19 at 10:43
  • 1
    @Loahrs I have added that to my answer. Yet instead of putting that into a comment, it might be better to ask that in another question? – cfrick Feb 05 '19 at 11:04