Is there a way to apply dynamic CSS with selectors via Vaadin Flow? Obviously, you can set CSS pretty easily in most circumstances. My specific problem is that I have dynamic background colors for elements that I want users to define themselves. And even then, it would be easy except for the colors differ between light and dark mode.
For example, I previously had this CSS in my styles.css:
html {
--section-background-color-01: #fc7c7c;
--section-background-color-02: #fcb67c;
--section-background-color-03: #fced7c;
--section-background-color-04: #dafc7c;
--section-background-color-05: #8bfc7c;
--section-background-color-06: #7cfce9;
--section-background-color-07: #7cc9fc;
--section-background-color-08: #7c7efc;
--section-background-color-09: #b37cfc;
--section-background-color-10: #fc7cfa;
--section-background-color-11: #fc7cd2;
--section-background-color-12: #fc7c9e;
}
html[theme~="dark"] {
--section-background-color-01: #420000;
--section-background-color-02: #422300;
--section-background-color-03: #414200;
--section-background-color-04: #174200;
--section-background-color-05: #004203;
--section-background-color-06: #004238;
--section-background-color-07: #001f42;
--section-background-color-08: #000042;
--section-background-color-09: #200042;
--section-background-color-10: #320042;
--section-background-color-11: #42003d;
--section-background-color-12: #42001e;
}
I was then applying it in my code as such:
VerticalLayout section1 = new VerticalLayout();
section1.getStyle().setBackgroundColor("var(--section-background-color-01)");
The problem is trying to address this dynamically whilst also accounting for the dark theme.
I can do the following:
String userSelectedColor = "#ffffff";
UI.getCurrent().getStyle().set("--section-background-color-01", userSelectedColor);
...
section1.getStyle().setBackgroundColor("var(--section-background-color-01)");
This does work, but the color is the same no matter what the theme is. This is not what I'm looking for. I need to have the color change between instances.
I should probably clarify, I don't have access to the light/dark mode server-side to be able to react dynamically. It's handled with a component from the directory, Theme Select - https://vaadin.com/directory/component/theme-select
This component is pure browser and I don't know if there even is a way to get the value from it. It's otherwise been completely ideal for our purposes.
I had a thought and tried the following CSS:
html {
--section-background-light-color-01: #fc7c7c;
--section-background-light-color-02: #fcb67c;
--section-background-light-color-03: #fced7c;
--section-background-light-color-04: #dafc7c;
--section-background-light-color-05: #8bfc7c;
--section-background-light-color-06: #7cfce9;
--section-background-light-color-07: #7cc9fc;
--section-background-light-color-08: #7c7efc;
--section-background-light-color-09: #b37cfc;
--section-background-light-color-10: #fc7cfa;
--section-background-light-color-11: #fc7cd2;
--section-background-light-color-12: #fc7c9e;
--section-background-dark-color-01: #420000;
--section-background-dark-color-02: #422300;
--section-background-dark-color-03: #414200;
--section-background-dark-color-04: #174200;
--section-background-dark-color-05: #004203;
--section-background-dark-color-06: #004238;
--section-background-dark-color-07: #001f42;
--section-background-dark-color-08: #000042;
--section-background-dark-color-09: #200042;
--section-background-dark-color-10: #320042;
--section-background-dark-color-11: #42003d;
--section-background-dark-color-12: #42001e;
}
html {
--section-background-color-01: var(--section-background-light-color-01);
--section-background-color-02: var(--section-background-light-color-02);
--section-background-color-03: var(--section-background-light-color-03);
--section-background-color-04: var(--section-background-light-color-04);
--section-background-color-05: var(--section-background-light-color-05);
--section-background-color-06: var(--section-background-light-color-06);
--section-background-color-07: var(--section-background-light-color-07);
--section-background-color-08: var(--section-background-light-color-08);
--section-background-color-09: var(--section-background-light-color-09);
--section-background-color-10: var(--section-background-light-color-10);
--section-background-color-11: var(--section-background-light-color-11);
--section-background-color-12: var(--section-background-light-color-12);
}
html[theme~="dark"] {
--section-background-color-01: var(--section-background-dark-color-01);
--section-background-color-02: var(--section-background-dark-color-02);
--section-background-color-03: var(--section-background-dark-color-03);
--section-background-color-04: var(--section-background-dark-color-04);
--section-background-color-05: var(--section-background-dark-color-05);
--section-background-color-06: var(--section-background-dark-color-06);
--section-background-color-07: var(--section-background-dark-color-07);
--section-background-color-08: var(--section-background-dark-color-08);
--section-background-color-09: var(--section-background-dark-color-09);
--section-background-color-10: var(--section-background-dark-color-10);
--section-background-color-11: var(--section-background-dark-color-11);
--section-background-color-12: var(--section-background-dark-color-12);
}
That works by itself. But my problem now is that my colors applied through Java are not working at all.
String userSelectedColorLight = "#ffffff";
String userSelectedColorDark = "#000000";
UI.getCurrent().getStyle().set("--section-background-light-color-01", userSelectedColorLight);
UI.getCurrent().getStyle().set("--section-background-dark-color-01", userSelectedColorDark);
...
section1.getStyle().setBackgroundColor("var(--section-background-color-01)");
The light/dark colors from above are not being applied. At best, only my default colors from the CSS are being applied. It would seem that I can't chain CSS variables through flow. At least, not as I'm currently doing it.
What is really frustrating me at this point is that I did find this bit of older Vaadin documentation - https://vaadin.com/docs/v8/framework/articles/DynamicallyInjectingCSS
It shows this example of doing exactly what I want:
select.addValueChangeListener(new ValueChangeListener() {
@Override
public void valueChange( ValueChangeEvent event ) {
// Get the new font family
String fontFamily = select.getValue().toString();
// Get the stylesheet of the page
Styles styles = Page.getCurrent().getStyles();
// inject the new font size as a style. We need .v-app to override Vaadin's default styles here
styles.add(".v-app .v-textarea.text-label { font-family:" + fontFamily + "; }");
}
});
A full CSS definition with the selector is able to be applied. That code, however, is for Vaadin 8, and does not seem to have an equivalent in Vaadin 24.
I need to have custom CSS that will dynamically react to the theme of the page (ie, dark/light mode). Is there a way that I can chain together CSS variable definitions globally for my current view (ala my '--section-background-light-color' and '--section-background-dark-color' attempt above), or is there a way that I can push a full CSS definition that includes the selectors?
UPDATE:
I got a workaround by simply injecting my desired result as raw HTML into my page:
{
ColorSettings sectionColors = getCurrentUser().getSectionColorSettings();
StringBuilder sb = new StringBuilder();
sb.append("<style>");
sb.append("html {");
sb.append("--section-background-color-01: ").append(sectionColors.getLightModeBackgroundColor01()).append(";");
sb.append("--section-background-color-02: ").append(sectionColors.getLightModeBackgroundColor02()).append(";");
sb.append("--section-background-color-03: ").append(sectionColors.getLightModeBackgroundColor03()).append(";");
sb.append("--section-background-color-04: ").append(sectionColors.getLightModeBackgroundColor04()).append(";");
sb.append("--section-background-color-05: ").append(sectionColors.getLightModeBackgroundColor05()).append(";");
sb.append("--section-background-color-06: ").append(sectionColors.getLightModeBackgroundColor06()).append(";");
sb.append("--section-background-color-07: ").append(sectionColors.getLightModeBackgroundColor07()).append(";");
sb.append("--section-background-color-08: ").append(sectionColors.getLightModeBackgroundColor08()).append(";");
sb.append("--section-background-color-09: ").append(sectionColors.getLightModeBackgroundColor09()).append(";");
sb.append("--section-background-color-10: ").append(sectionColors.getLightModeBackgroundColor10()).append(";");
sb.append("--section-background-color-11: ").append(sectionColors.getLightModeBackgroundColor11()).append(";");
sb.append("--section-background-color-12: ").append(sectionColors.getLightModeBackgroundColor12()).append(";");
sb.append("}");
sb.append("html[theme~=\"dark\"] {");
sb.append("--section-background-color-01: ").append(sectionColors.getDarkModeBackgroundColor01()).append(";");
sb.append("--section-background-color-02: ").append(sectionColors.getDarkModeBackgroundColor02()).append(";");
sb.append("--section-background-color-03: ").append(sectionColors.getDarkModeBackgroundColor03()).append(";");
sb.append("--section-background-color-04: ").append(sectionColors.getDarkModeBackgroundColor04()).append(";");
sb.append("--section-background-color-05: ").append(sectionColors.getDarkModeBackgroundColor05()).append(";");
sb.append("--section-background-color-06: ").append(sectionColors.getDarkModeBackgroundColor06()).append(";");
sb.append("--section-background-color-07: ").append(sectionColors.getDarkModeBackgroundColor07()).append(";");
sb.append("--section-background-color-08: ").append(sectionColors.getDarkModeBackgroundColor08()).append(";");
sb.append("--section-background-color-09: ").append(sectionColors.getDarkModeBackgroundColor09()).append(";");
sb.append("--section-background-color-10: ").append(sectionColors.getDarkModeBackgroundColor10()).append(";");
sb.append("--section-background-color-11: ").append(sectionColors.getDarkModeBackgroundColor11()).append(";");
sb.append("--section-background-color-12: ").append(sectionColors.getDarkModeBackgroundColor12()).append(";");
sb.append("}");
sb.append("</style>");
Html style = new Html(sb.toString());
UI.getCurrent().addComponentAsFirst(style);
}
This works, but there has to be a better way to do this, right? Something proper via Vaadin?