Import additional style sheets to customize component themes and style application views.
Prerequisites
You should be familiar with Style Scopes, to know whether you need to import a style sheet to the global scope or to a component scope.
To learn how static resources are handled, including where CSS files should be placed in your project, see Storing and Loading Resources.
Example
In server-side views (Java), use the @CssImport annotation to import local/bundled style sheets and the @StyleSheet annotation to import external/linked style sheets.
The @CssImport annotation can also be used to import component-specific style sheets.
Source code
ImportingStyleSheets.java
package com.vaadin.flow.tutorial.theme;
import com.vaadin.flow.component.dependency.CssImport;
import com.vaadin.flow.component.dependency.StyleSheet;
import com.vaadin.flow.component.html.Div;
import com.vaadin.flow.router.Route;
import com.vaadin.flow.tutorial.annotations.CodeFor;
@CodeFor("../../themes/importing-style-sheets.asciidoc")
public class ImportingStyleSheets {
@Route(value = "")
// Import a style sheet into the global scope
@CssImport("./styles/shared-styles.css")
@CssImport(value = "./styles/shared-styles.css", include = "common-styles")
@CssImport(value = "./styles/shared-typography.css",
id = "shared-typography")
@CssImport(value = "./styles/shared-styles.css",
include = "shared-typography")
// Import a style sheet into the local scope of the TextField component
@CssImport(value = "./styles/text-field.css",
themeFor = "vaadin-text-field")
@CssImport(value = "./styles/shared-overlays.css",
themeFor = "vaadin-select-overlay vaadin-combo-box-overlay")
@CssImport(value = "./styles/shared-styles.css",
include = "shared-typography",
themeFor = "vaadin-confirm-dialog-overlay")
// Link to external style sheets
@StyleSheet("context://custom-font.css")
@StyleSheet("https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css")
public class MyApplication extends Div {
}
}
ImportStyleSheets.js
// tutorial::../documentation-themes/importing-style-sheets.asciidoc
// Import the function that allows you to register style sheets for components
import { registerStyles } from '@vaadin/vaadin-themable-mixin/register-styles.js';
// Import the tagged template function that is used to define
// a multi-line CSS string
import { css } from '@vaadin/vaadin-themable-mixin/register-styles.js';
// Define and register a style sheet for the <vaadin-text-field> component
registerStyles('vaadin-text-field', css`
[part="input-field"] {
border: 1px solid;
...
}
`);
// Register the same style sheet for both the <vaadin-select-overlay>
// and the <vaadin-combo-box-overlay> elements
registerStyles('vaadin-select-overlay vaadin-combo-box-overlay', css`
/* Styles which will be imported in
vaadin-select-overlay and vaadin-combo-box-overlay
local style scopes */
`);
// Define and export a string of reusable CSS
export default css`
h1 {
font-weight: 300;
font-size: 40px;
}
h2 {
font-weight: 300;
font-size: 32px;
}
h3 {
font-weight: 400;
font-size: 24px;
}
`;
// Import a string of shared CSS
import sharedTypography from 'styles/shared-typography.css.js';
// Create a new <style> element and add the shared CSS to it.
const style = document.createElement('style');
style.innerHTML = sharedTypography.toString();
// Add the new style sheet to the global scope (document)
document.head.appendChild(style);
// Register the shared typography styles for
// the <vaadin-confirm-dialog-overlay> element
registerStyles('vaadin-confirm-dialog-overlay', sharedTypography);
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
class MyView extends PolymerElement {
static get template() {
return html`
${sharedTypography}
<h2>My view title</h2>
...
`;
}
static get is() {
return 'my-view';
}
}
customElements.define(MyView.is, MyView);
// Import a theme-specific component, for example <vaadin-button>
import '@vaadin/vaadin-button/theme/lumo/vaadin-button.js';
// Import the color style sheet if you are using some of
// the custom color properties Lumo offers
import '@vaadin/vaadin-lumo-styles/color.js';
ImportStyleSheets.html
tutorial::../documentation-themes/importing-style-sheets.asciidoc
<link rel="stylesheet" type="text/css" href="/custom-font.css">
<link rel="stylesheet" type="text/css" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
<style>
/* Your CSS here */
</style>
<script type="module">
import '@polymer/polymer/lib/elements/custom-style.js';
</script>
<custom-style>
<style>
/* The CSS here will be scoped and won't
affect internal component styles */
</style>
</custom-style>
Global Styles
There are two ways to import style sheets to the global scope:
Local/bundled style sheets, which are loaded with the application’s frontend bundle, together with all JavaScript.
External/linked style sheets, which are not bundled with the application’s frontend bundle but loaded and cached separately by the browser.
Local Style Sheets
Local/bundled style sheets are inlined to the application bundle during a production build, together with other client-side resources.
Bundling is recommended for styles that change together with the application logic or component implementations, as the browser can cache them as a single unit made of closely related resources.
In server-side views (Java), the @CssImport annotation will handle all the boilerplate for you, you only need to reference a regular CSS file.
Caution
The @CssImport annotation does not work in Vaadin 14 compatibility mode (Bower and HTML imports).
Source code
ImportingStyleSheets.java
package com.vaadin.flow.tutorial.theme;
import com.vaadin.flow.component.dependency.CssImport;
import com.vaadin.flow.component.dependency.StyleSheet;
import com.vaadin.flow.component.html.Div;
import com.vaadin.flow.router.Route;
import com.vaadin.flow.tutorial.annotations.CodeFor;
@CodeFor("../../themes/importing-style-sheets.asciidoc")
public class ImportingStyleSheets {
@Route(value = "")
// Import a style sheet into the global scope
@CssImport("./styles/shared-styles.css")
@CssImport(value = "./styles/shared-styles.css", include = "common-styles")
@CssImport(value = "./styles/shared-typography.css",
id = "shared-typography")
@CssImport(value = "./styles/shared-styles.css",
include = "shared-typography")
// Import a style sheet into the local scope of the TextField component
@CssImport(value = "./styles/text-field.css",
themeFor = "vaadin-text-field")
@CssImport(value = "./styles/shared-overlays.css",
themeFor = "vaadin-select-overlay vaadin-combo-box-overlay")
@CssImport(value = "./styles/shared-styles.css",
include = "shared-typography",
themeFor = "vaadin-confirm-dialog-overlay")
// Link to external style sheets
@StyleSheet("context://custom-font.css")
@StyleSheet("https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css")
public class MyApplication extends Div {
}
}
ImportStyleSheets.html
tutorial::../documentation-themes/importing-style-sheets.asciidoc
<link rel="stylesheet" type="text/css" href="/custom-font.css">
<link rel="stylesheet" type="text/css" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
<style>
/* Your CSS here */
</style>
<script type="module">
import '@polymer/polymer/lib/elements/custom-style.js';
</script>
<custom-style>
<style>
/* The CSS here will be scoped and won't
affect internal component styles */
</style>
</custom-style>
External Style Sheets
External/linked style sheets can be used to import styles without inlining the contents to the application bundle.
This allows the browser to load and cache the style sheet separately from the rest of the application.
External style sheets need to be accessible from a URL, and therefore need to be placed in the public resource folder in your web application.
They can also come from outside your web application, for example from a different domain or a Content Delivery Network (CDN).
In server-side views (Java), the @StyleSheet annotation can be used to import style sheets from an external URL, or from a URL within your application. The latter type of URLs are prefixed with context://, which points to the root of the public resources folder of your application.
Source code
ImportingStyleSheets.java
package com.vaadin.flow.tutorial.theme;
import com.vaadin.flow.component.dependency.CssImport;
import com.vaadin.flow.component.dependency.StyleSheet;
import com.vaadin.flow.component.html.Div;
import com.vaadin.flow.router.Route;
import com.vaadin.flow.tutorial.annotations.CodeFor;
@CodeFor("../../themes/importing-style-sheets.asciidoc")
public class ImportingStyleSheets {
@Route(value = "")
// Import a style sheet into the global scope
@CssImport("./styles/shared-styles.css")
@CssImport(value = "./styles/shared-styles.css", include = "common-styles")
@CssImport(value = "./styles/shared-typography.css",
id = "shared-typography")
@CssImport(value = "./styles/shared-styles.css",
include = "shared-typography")
// Import a style sheet into the local scope of the TextField component
@CssImport(value = "./styles/text-field.css",
themeFor = "vaadin-text-field")
@CssImport(value = "./styles/shared-overlays.css",
themeFor = "vaadin-select-overlay vaadin-combo-box-overlay")
@CssImport(value = "./styles/shared-styles.css",
include = "shared-typography",
themeFor = "vaadin-confirm-dialog-overlay")
// Link to external style sheets
@StyleSheet("context://custom-font.css")
@StyleSheet("https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css")
public class MyApplication extends Div {
}
}
ImportStyleSheets.html
tutorial::../documentation-themes/importing-style-sheets.asciidoc
<link rel="stylesheet" type="text/css" href="/custom-font.css">
<link rel="stylesheet" type="text/css" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
<style>
/* Your CSS here */
</style>
<script type="module">
import '@polymer/polymer/lib/elements/custom-style.js';
</script>
<custom-style>
<style>
/* The CSS here will be scoped and won't
affect internal component styles */
</style>
</custom-style>
Caution
The CSS rules in external style sheets are not protected from overriding component-specific styles in browsers without native style encapsulation (shadow DOM) – namely Internet Explorer 11.
Use local style sheets in cases where this might be an issue, for example when including CSS which is not maintained by you.
Component Styles
These instructions apply to components that use ThemableMixin, including all Vaadin components.
Component styles are scoped per component and allow you to customize components without worrying about side-effects to other parts of your application.
Component styles are always inlined to the application bundle – they can’t be external/linked style sheets.
Component-scoped style sheets apply to all instances of the component across the entire application.
In server-side views, use the @CssImport annotation.
Refer to a .css file and specify the tag/element name of the component you wish to apply the style sheet to.
Source code
ImportingStyleSheets.java
package com.vaadin.flow.tutorial.theme;
import com.vaadin.flow.component.dependency.CssImport;
import com.vaadin.flow.component.dependency.StyleSheet;
import com.vaadin.flow.component.html.Div;
import com.vaadin.flow.router.Route;
import com.vaadin.flow.tutorial.annotations.CodeFor;
@CodeFor("../../themes/importing-style-sheets.asciidoc")
public class ImportingStyleSheets {
@Route(value = "")
// Import a style sheet into the global scope
@CssImport("./styles/shared-styles.css")
@CssImport(value = "./styles/shared-styles.css", include = "common-styles")
@CssImport(value = "./styles/shared-typography.css",
id = "shared-typography")
@CssImport(value = "./styles/shared-styles.css",
include = "shared-typography")
// Import a style sheet into the local scope of the TextField component
@CssImport(value = "./styles/text-field.css",
themeFor = "vaadin-text-field")
@CssImport(value = "./styles/shared-overlays.css",
themeFor = "vaadin-select-overlay vaadin-combo-box-overlay")
@CssImport(value = "./styles/shared-styles.css",
include = "shared-typography",
themeFor = "vaadin-confirm-dialog-overlay")
// Link to external style sheets
@StyleSheet("context://custom-font.css")
@StyleSheet("https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css")
public class MyApplication extends Div {
}
}
ImportStyleSheets.js
// tutorial::../documentation-themes/importing-style-sheets.asciidoc
// Import the function that allows you to register style sheets for components
import { registerStyles } from '@vaadin/vaadin-themable-mixin/register-styles.js';
// Import the tagged template function that is used to define
// a multi-line CSS string
import { css } from '@vaadin/vaadin-themable-mixin/register-styles.js';
// Define and register a style sheet for the <vaadin-text-field> component
registerStyles('vaadin-text-field', css`
[part="input-field"] {
border: 1px solid;
...
}
`);
// Register the same style sheet for both the <vaadin-select-overlay>
// and the <vaadin-combo-box-overlay> elements
registerStyles('vaadin-select-overlay vaadin-combo-box-overlay', css`
/* Styles which will be imported in
vaadin-select-overlay and vaadin-combo-box-overlay
local style scopes */
`);
// Define and export a string of reusable CSS
export default css`
h1 {
font-weight: 300;
font-size: 40px;
}
h2 {
font-weight: 300;
font-size: 32px;
}
h3 {
font-weight: 400;
font-size: 24px;
}
`;
// Import a string of shared CSS
import sharedTypography from 'styles/shared-typography.css.js';
// Create a new <style> element and add the shared CSS to it.
const style = document.createElement('style');
style.innerHTML = sharedTypography.toString();
// Add the new style sheet to the global scope (document)
document.head.appendChild(style);
// Register the shared typography styles for
// the <vaadin-confirm-dialog-overlay> element
registerStyles('vaadin-confirm-dialog-overlay', sharedTypography);
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
class MyView extends PolymerElement {
static get template() {
return html`
${sharedTypography}
<h2>My view title</h2>
...
`;
}
static get is() {
return 'my-view';
}
}
customElements.define(MyView.is, MyView);
// Import a theme-specific component, for example <vaadin-button>
import '@vaadin/vaadin-button/theme/lumo/vaadin-button.js';
// Import the color style sheet if you are using some of
// the custom color properties Lumo offers
import '@vaadin/vaadin-lumo-styles/color.js';
You can use the same style sheet for multiple components simultaneously by providing a space-separated list of component names instead of a single component name. Wildcard element names are supported as well, for example, vaadin-*-overlay.
Source code
ImportingStyleSheets.java
package com.vaadin.flow.tutorial.theme;
import com.vaadin.flow.component.dependency.CssImport;
import com.vaadin.flow.component.dependency.StyleSheet;
import com.vaadin.flow.component.html.Div;
import com.vaadin.flow.router.Route;
import com.vaadin.flow.tutorial.annotations.CodeFor;
@CodeFor("../../themes/importing-style-sheets.asciidoc")
public class ImportingStyleSheets {
@Route(value = "")
// Import a style sheet into the global scope
@CssImport("./styles/shared-styles.css")
@CssImport(value = "./styles/shared-styles.css", include = "common-styles")
@CssImport(value = "./styles/shared-typography.css",
id = "shared-typography")
@CssImport(value = "./styles/shared-styles.css",
include = "shared-typography")
// Import a style sheet into the local scope of the TextField component
@CssImport(value = "./styles/text-field.css",
themeFor = "vaadin-text-field")
@CssImport(value = "./styles/shared-overlays.css",
themeFor = "vaadin-select-overlay vaadin-combo-box-overlay")
@CssImport(value = "./styles/shared-styles.css",
include = "shared-typography",
themeFor = "vaadin-confirm-dialog-overlay")
// Link to external style sheets
@StyleSheet("context://custom-font.css")
@StyleSheet("https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css")
public class MyApplication extends Div {
}
}
ImportStyleSheets.js
// tutorial::../documentation-themes/importing-style-sheets.asciidoc
// Import the function that allows you to register style sheets for components
import { registerStyles } from '@vaadin/vaadin-themable-mixin/register-styles.js';
// Import the tagged template function that is used to define
// a multi-line CSS string
import { css } from '@vaadin/vaadin-themable-mixin/register-styles.js';
// Define and register a style sheet for the <vaadin-text-field> component
registerStyles('vaadin-text-field', css`
[part="input-field"] {
border: 1px solid;
...
}
`);
// Register the same style sheet for both the <vaadin-select-overlay>
// and the <vaadin-combo-box-overlay> elements
registerStyles('vaadin-select-overlay vaadin-combo-box-overlay', css`
/* Styles which will be imported in
vaadin-select-overlay and vaadin-combo-box-overlay
local style scopes */
`);
// Define and export a string of reusable CSS
export default css`
h1 {
font-weight: 300;
font-size: 40px;
}
h2 {
font-weight: 300;
font-size: 32px;
}
h3 {
font-weight: 400;
font-size: 24px;
}
`;
// Import a string of shared CSS
import sharedTypography from 'styles/shared-typography.css.js';
// Create a new <style> element and add the shared CSS to it.
const style = document.createElement('style');
style.innerHTML = sharedTypography.toString();
// Add the new style sheet to the global scope (document)
document.head.appendChild(style);
// Register the shared typography styles for
// the <vaadin-confirm-dialog-overlay> element
registerStyles('vaadin-confirm-dialog-overlay', sharedTypography);
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
class MyView extends PolymerElement {
static get template() {
return html`
${sharedTypography}
<h2>My view title</h2>
...
`;
}
static get is() {
return 'my-view';
}
}
customElements.define(MyView.is, MyView);
// Import a theme-specific component, for example <vaadin-button>
import '@vaadin/vaadin-button/theme/lumo/vaadin-button.js';
// Import the color style sheet if you are using some of
// the custom color properties Lumo offers
import '@vaadin/vaadin-lumo-styles/color.js';