Styles
- Define scoped stylesheets
- Define scoped styles in the template
- Use lit-html’s styleMap and classMap functions
- Theming
Define scoped stylesheets
Scoped stylesheets are stylesheets that only style instances of the component in which they are defined.
Scoped stylesheets can style:
- Shadow root contents (the element’s rendered template).
- The host element (the element that owns the shadow root).
- Slotted children (light DOM content rendered via a
<slot>
).
For optimal performance, we recommend placing scoped stylesheets in a static styles
property. To do this, import the css
helper function from the lit-element
module and create a static styles
property. Then, write styles in standard CSS.
// Import the `css` helper function
import { LitElement, css, html } from 'lit-element';
class MyElement extends LitElement {
static get styles() {
return css`
/* Scoped styles go here */
`;
}
render() {
return html`
<!-- Template goes here -->
`;
}
}
The value of the static styles
property can be:
-
A single tagged template literal.
static get styles() { return css`...`; }
-
An array of tagged template literals.
static get styles() { return [ css`...`, css`...`]; }
Using an array of tagged template literals, a component can inherit the styles from a LitElement superclass, and add its own styles:
class MyElement extends SuperElement { static get styles() { return [ super.styles, css`...` ]; } }
Style shadow root contents
LitElement templates are rendered into a shadow root by default. Styles scoped to an element’s shadow root don’t affect the main document. Similarly, with the exception of inherited CSS properties, document-level styles do not affect the contents of a shadow root.
To style content in a shadow root, create a static styles
property and write styles using standard CSS selectors:
class MyElement extends LitElement {
static get styles() {
// Write styles in standard CSS
return css`
* { color: red; }
p { font-family: sans-serif; }
.myclass { margin: 100px; }
#main { padding: 30px; }
h1 { font-size: 4em; }
`;
}
render() {
return html`
<p>Hello World</p>
<p class="myclass">Hello World</p>
<p id="main">Hello World</p>
<h1>Hello World</h1>
`;
}
}
Style the host element
The host element is the container element for a rendered LitElement component. To create default styles for the host element, use the :host
CSS pseudo-selector and ::host()
CSS pseudo-class.
-
:host
selects the host element. -
:host(selector)
selects the host element, but only if the host element matches selector.
static get styles() {
return css`
/* Selects the host element */
:host {
display: block;
}
/* Selects the host element if it is hidden */
:host([hidden]) {
display: none;
}
/* Selects the host element if it has class "blue" */
:host(.blue) {
background-color: aliceblue;
color: blue;
}
`;
}
Style slotted content
The <slot>
element acts as a placeholder in a LitElement template. For example:
class MyElement extends LitElement {
render() {
return html`<slot></slot>`;
}
}
<my-element><p>Slotted content</p></my-element>
Use the ::slotted()
CSS pseudo-element to select elements that are included in your template via <slot>
s.
-
::slotted(*)
matches all slotted elements. -
::slotted(p)
matches slotted paragraphs. -
p ::slotted(*)
matches slotted elements in a paragraph element.
import { LitElement, html, css } from 'lit-element';
class MyElement extends LitElement {
static get styles() {
return css`
::slotted(*) { font-family: Roboto; }
::slotted(p) { color: blue; }
div ::slotted(*) { color: red; }
`;
}
render() {
return html`
<slot></slot>
<div><slot name="hi"></slot></div>
`;
}
}
customElements.define('my-element', MyElement);
Note that only direct slotted children can be styled with ::slotted()
.
<my-element>
<div>Stylable with ::slotted()</div>
</my-element>
<my-element>
<div><p>Not stylable with ::slotted()</p></div>
</my-element>
Watch out for Shady CSS limitations around slotted content! See the Shady CSS limitations for details on how to use the ::slotted()
syntax in a polyfill-friendly way.
Configurable styles with custom properties
Static styles are evaluated once per class. To style instances of a component using static styles, use CSS variables and custom properties:
static get styles() {
return css`
:host { color: var(--themeColor); }
`;
}
<style>
html {
--themeColor: #123456;
}
</style>
<my-element></my-element>
See the section on CSS custom properties for more information.
Expressions in static styles
Static styles apply to all instances of a component. Any expressions in CSS are evaluated once, then reused for all instances.
Consider using CSS variables and custom properties to create configurable styles. CSS cusom properties work well with app themes, and also allow you to create per-instance styles.
To prevent LitElement-based components from evaluating potentially malicious code, the css
tag only accepts literal strings. With expressions, you can nest css
literals:
import { LitElement, html, css } from 'lit-element';
const mainColor = css`red`;
class MyElement extends LitElement {
static get styles() {
return css`
div { color: ${mainColor} }
`;
}
render() {
return html`<div>Some content in a div</div>`;
}
}
customElements.define('my-element', MyElement);
However, if you want to use expressions to add a non-literal to a css
literal, you must wrap the non-literal with the unsafeCSS
function. For example:
import { LitElement, html, css, unsafeCSS } from 'lit-element';
class MyElement extends LitElement {
static get styles() {
const mainColor = 'red';
return css`
div { color: ${unsafeCSS(mainColor)} }
`;
}
render() {
return html`<div>Some content in a div</div>`;
}
}
customElements.define('my-element', MyElement);
Another example:
import { LitElement, css, unsafeCSS } from 'lit-element';
class MyElement extends LitElement {
static get styles() {
const mainWidth = 800;
const padding = 20;
return css`
:host {
width: ${unsafeCSS(mainWidth + padding)}px;
}
`;
}
}
Only use the unsafeCSS
tag with trusted input. To prevent LitElement-based components from evaluating potentially malicious code, the css
tag only accepts literal strings. unsafeCSS
circumvents this safeguard, so use it with caution.
Define scoped styles in the template
In a style element
We recommend using static styles for optimal performance. However, static styles are evaluated once per class. Sometimes, you might need to evaluate styles per instance.
We recommend using CSS properties to create customizable styles. However, you can also include <style>
elements in a LitElement template. These are updated per instance.
render() {
return html`
<style>
/* updated per instance */
</style>
<div>template content</div>
`;
}
Expressions and style elements
The most intuitive way to evaluate per-instance styles has some important limitations and performance issues. We consider the example below to be an anti-pattern:
// Anti-pattern!
render() {
return html`
<style>
:host {
color: ${/* Limitations & performance issues! */}
}
</style>
<div>template content</div>
`;
}
Expressions inside a <style>
element won’t update per instance in ShadyCSS, due to limitations of the ShadyCSS polyfill. See the ShadyCSS readme for more information.
Additionally, evaluating an expression inside a <style>
element is inefficient. When any text inside a <style>
element changes, the browser must re-parse the whole <style>
element, resulting in unnecessary rework.
If you need to evaluate expressions inside a <style>
element, use the following strategy to avoid creating performance problems:
-
Separate styles that require per-instance evaluation from those that don’t.
-
Evaluate per-instance CSS properties by creating an expression that captures that property inside a complete
<style>
block. Include it in your template.
Example
import { LitElement, html } from 'lit-element';
const perClassStyle = html`
<style>
:host {
display: block;
font-family: Roboto;
font-size: 14px;
}
</style>
`;
const blueText = html`
<style> :host { color: blue; } </style>
`;
const redText = html`
<style> :host { color: red; } </style>
`;
class MyElement extends LitElement {
constructor() {
super();
this.perInstanceStyle = redText;
}
render() {
return html`
${perClassStyle}
${this.perInstanceStyle}
<div>Hello World</div>
`;
}
}
customElements.define('my-element', MyElement);
In an external stylesheet
We recommend placing your styles in a static styles
property for optimal performance. However, you can include an external stylesheet in your template with a <link>
:
import { LitElement, html } from 'lit-element';
class MyElement extends LitElement {
render() {
return html`
<link rel="stylesheet" href="./app-styles.css">
<button>a button</button>
<div>a div</div>
`;
}
}
customElements.define('my-element', MyElement);
There are some important caveats though:
-
The ShadyCSS polyfill doesn’t support external stylesheets.
-
External styles can cause a flash-of-unstyled-content (FOUC) while they load.
-
The URL in the
href
attribute is relative to the main document. This is okay if you’re building an app and your asset URLs are well-known, but avoid using external stylesheets when building a reusable element.
Use lit-html’s styleMap and classMap functions
LitElement is based on the lit-html templating library, which offers two functions, classMap
and styleMap
, to conveniently apply classes and styles in HTML templates.
For more information on these and other lit-html directives, see the documentation on lit-html built-in directives.
To use styleMap
and/or classMap
:
-
Install the
lit-html
package, and add it as a dependency of your project:npm install --save lit-html
-
Import
classMap
and/orstyleMap
:import { classMap } from 'lit-html/directives/class-map'; import { styleMap } from 'lit-html/directives/style-map';
-
Use
classMap
and/orstyleMap
in your element template:constructor() { super(); this.classes = { mydiv: true, someclass: true }; this.styles = { color: 'green', fontFamily: 'Roboto' }; } render() { return html` <div class=${classMap(this.classes)} style=${styleMap(this.styles)}> Some content </div> `; }
classMap syntax
classMap
applies a set of classes to an HTML element:
<div class=${classMap({alert:true,info:true})}>Content.</div>
<!-- Equivalent: <div class="alert info">Content.</div> -->
styleMap syntax
styleMap
applies a set of CSS rules to an HTML element:
<button style=${styleMap({
backgroundColor: 'blue',
border: '1px solid black'
})}>A button</button>
<!-- Equivalent:
<button style="
background-color:blue;
border: 1px solid black;
">A button</button>
-->
To refer to hyphenated properties such as font-family
, use the camelCase equivalent (fontFamily
) or place the hyphenated property name in quotes ('font-family'
).
To refer to custom CSS properties such as --custom-color
, place the whole property name in quotes ('--custom-color'
).
Inline style or CSS | styleMap equivalent |
---|---|
background-color: blue; |
backgroundColor: 'blue' or 'background-color': 'blue' |
font-family: Roboto, Arial, sans-serif; |
fontFamily: 'Roboto, Arial, sans-serif' or 'font-family': 'Roboto, Arial, sans-serif' |
--custom-color: #FFFABC; |
'--custom-color': '#FFFABC;' |
--otherCustomColor: #FFFABC; |
'--otherCustomColor': '#FFFABC;' |
color: var(--customprop, blue); |
color: 'var(--customprop, blue)' |
Examples
Inline style syntax:
<div style="
background-color:blue;
font-family:Roboto;
--custom-color:#e26dd2;
--otherCustomColor:#77e26d;">
</div>
Equivalent CSS syntax:
div {
background-color: blue;
font-family: Roboto;
--custom-color: #e26dd2;
--otherCustomColor: #77e26d;
}
Equivalent styleMap
syntax:
html`
<div style=${styleMap({
'background-color': 'blue',
fontFamily: 'Roboto',
'--custom-color': '#e26dd2',
'--otherCustomColor': '#77e26d'
})}></div>
`
Theming
-
Use CSS inheritance to propagate style information to LitElement components and their rendered templates.
<style> html { --themeColor: #123456; font-family: Roboto; } </style> <!-- host inherits `--themeColor` and `font-family` and passes these properties to its rendered template --> <my-element></my-element>
-
Use CSS variables and custom properties to configure styles per-instance.
<style> html { --my-element-background-color: /* some color */; } .stuff { --my-element-background-color: /* some other color */; } </style> <my-element></my-element> <my-element class="stuff"></my-element>
// MyElement's static styles static get styles() { return css` :host { background-color: var(--my-element-background-color); } `; }
CSS inheritance
CSS inheritance lets parent and host elements propagate certain CSS properties to their descendents.
Not all CSS properties inherit. Inherited CSS properties include:
color
andbackground-color
font-family
and otherfont-*
properties- All CSS custom properties (
--*
)
See CSS Inheritance on MDN for more information.
You can use CSS inheritance to set styles on an ancestor element that are inherited by its descendents:
<style>
html {
font-family: Roboto;
}
</style>
<div>
<p>Uses Roboto</p>
</div>
Similarly, host elements pass down inheritable CSS properties to their rendered templates.
You can use the host element’s type selector to style it:
<style>
my-element { font-family: Roboto; }
</style>
<my-element></my-element>
class MyElement extends LitElement {
render() {
return html`<p>Uses Roboto</p>`;
}
}
You can also use the :host
CSS pseudo-class to style the host from inside its own template:
static get styles() {
return css`
:host {
font-family: Roboto;
}
`;
}
render() {
return html`
<p>Uses Roboto</p>
`;
}
Type selectors have higher specificity than :host.
An element type selector has higher specificity than the :host
pseudo-class selector. Styles set for a custom element tag will override styles set with :host
and :host()
:
<style>
my-element { font-family: Courier; }
</style>
<my-element></my-element>
class MyElement extends LitElement {
static get styles() {
return css`:host { font-family: Roboto; }`
}
render() {
return html`<p>Will use courier</p>`;
}
}
Any properties that a host element inherits will also be inherited by the elements in its template:
<style>
div { font-family: Roboto; }
</style>
<div><my-element></my-element></div>
class MyElement extends LitElement {
render() {
return html`<p>Uses Roboto</p>`;
}
}
CSS custom properties
All CSS custom properties (--custom-property-name
) inherit. You can use this to make your component’s styles configurable from outside.
The following component sets its background color to a CSS variable. The CSS variable uses the value of --my-background
if it’s available, and otherwise defaults to yellow
:
class MyElement extends LitElement {
static get styles() {
return css`
:host {
background-color: var(--my-background, yellow);
}
`;
}
render() {
return html`<p>Hello world</p>`;
}
}
Users of this component can set the value of --my-background
, using the my-element
tag as a CSS selector:
<style>
my-element {
--my-background: rgb(67, 156, 144);
}
</style>
<my-element></my-element>
--my-background
is configurable per instance of my-element
:
<style>
my-element {
--my-background: rgb(67, 156, 144);
}
my-element.stuff {
--my-background: #111111;
}
</style>
<my-element></my-element>
<my-element class="stuff"></my-element>
If a component user has an existing app theme, they can easily set the host’s configurable properties to use theme properties:
<html>
<head>
<title>lit-element code sample</title>
<script type="module" src="./my-element.js"></script>
<style>
html { --themeColor1: rgb(67, 156, 144); }
my-element {
--myBackground: var(--themeColor1);
--myColor: rgb(156, 67, 152);
}
</style>
</head>
<body>
<my-element></my-element>
</body>
</html>
See CSS Custom Properties on MDN for more information.
A simple example theme
index.html
<html>
<head>
<script type="module" src="./my-element.js"></script>
<title>lit-element code sample</title>
<style>
html {
--theme-primary: green;
--theme-secondary: aliceblue;
--theme-warning: red;
--theme-font-family: Roboto;
}
my-element {
--my-element-text-color: var(--theme-primary);
--my-element-background-color: var(--theme-secondary);
--my-element-font-family: var(--theme-font-family);
}
.warning {
--my-element-text-color: var(--theme-warning);
}
</style>
</head>
<body>
<my-element></my-element>
<my-element class="warning"></my-element>
</body>
</html>
my-element.js
import { LitElement, html, css } from 'lit-element';
class MyElement extends LitElement {
static get styles() {
return css`
:host {
display: block;
color: var(--my-element-text-color, black);
background: var(--my-element-background-color, white);
font-family: var(--my-element-font-family, Roboto);
}
:host([hidden]) {
display: none;
}
`;
}
render() {
return html`<div>Hello World</div>`;
}
}
customElements.define('my-element', MyElement);