Styling Web Components with Vaadin
Summarizing ways to style both Vaadin and non-Vaadin components here. Important: The @CssImport
annotation
only works with web components implementing the ThemableMixin
(so, in general, only with Vaadin components)
AND/OR web components correctly defining parts in their ShadowDOM.
@CssImport
can not be used with other web components - it will simply get ignored and will do nothing.
Vaadin 23 and lower
In order to style the components, you need to “pierce the ShadowDOM veil” and inject
CSS into the ShadowDOM of the component, otherwise things won’t work. The following ways are only possible
for Vaadin components (or for components implementing the ThemableMixin
):
- The best way is to create a theme for your app and place the css into the
components/
folder. For example if you’re stylingvaadin-button
then placevaadin-button.css
intocomponents/
folder and Vaadin theming engine will automatically inject that CSS into Button’s ShadowDOM. See Creating Custom Themes for more details. - Alternatively add
@CssImport(value = "./css/foo.css", themeFor = "vaadin-button")
into a@Route
-annotated class in your project.
Non-Vaadin components
For other web components (web components not implementing ThemableMixin
mixin), you can use tricks mentioned at Vaadin Docs #790.
For example you can simply inject new <style>
element into shadow-dom from Java as follows:
calendar.getElement().executeJs("var s = document.createElement(\"style\"); s.textContent = $0; this.shadowRoot.appendChild(s);", ".fc-timegrid-slots { background: red }");
Alternatively, extend the class in javascript and add the styles manually, as described at https://vaadin.com/directory/component/full-calendar-flow/samples , the “using a custom class” example.
Vaadin 24
Vaadin 24 changed the way ShadowDOM is pierced. It now uses direct support of CSS for styling parts via
::part(input-field)
, see Styling Components.
This should work with all web components that contain elements with part="xyz"
attributes in their ShadowDOM;
then you can target those via
vaadin-button::parts(xyz) {
background: red;
}
There’s no need to include such CSS in a special way - you can add rules directly to your my-theme/styles.css
file, or even to @CssImport("./foo.css")
if you’re not using Application Themes.
This will work regardless of whether the web component implements the ThemableMixin
or not.
If the web component doesn’t implement the ThemableMixin
AND it does not define parts (this is the case for example for the
Google Map Addon), the only way is to use workarounds
mentioned above in the “Non-Vaadin components” chapter - e.g. the <style>
injection.