Styles

This page is a guide to the styling options available for LitElement components.

If you’re using the Shady CSS polyfill, be aware that it has some limitations. See the Shady CSS README for more information.

Styling options for component developers

The shadow DOM API allows the creation of encapsulated DOM trees that are attached to a custom element.

The root node of a shadow DOM tree is called the shadow root. The element in the main document that has a shadow root attached to it is called the host element, or host.

By default, LitElement creates a shadow root for your host element. LitElement renders the DOM structure described in your element template into this shadow root.

Shadow DOM scopes CSS so that styles defined in a shadow root only apply to DOM inside the shadow root, and do not “leak” to outside DOM. With the exception of inherited CSS properties, shadow roots are also isolated from styles defined outside the shadow root, whether in the main page or an outer shadow root.

This section describes how to create styles in your shadow root to style your host element and its shadow DOM.

Where to define your styles

There are three main places in which you can define styles for your host element and its shadow DOM:

Define styles in a static styles property

LitElement lets you define static styles that apply to all instances of a component.

We recommend using static styles for optimal performance. LitElement uses Constructable Stylesheets in browsers that support it, with a fallback for browsers that don’t. Constructable Stylesheets allow the browser to parse styles exactly once and reuse the resulting Stylesheet object for maximum efficiency.

The styles in the static styles property are evaluated once only and applied to all instances of the element. You can modify styles per element instance by using CSS custom properties:

If you don’t want to use custom properties, you can define per-instance styles in a <style> element inside shadow DOM. See the section on Defining your styles in a style element for more information.

To define a static styles property:

  1. Import the css helper function from the lit-element module:

    import {LitElement, css} from 'lit-element';
    
  2. Create a static styles property and define your styles in plain CSS.

    The value of the static styles property can be:

    • A single tagged template literal:

      class MyElement extends LitElement {
        static get styles() {
          return css`
          :host {
            display: block;
          }`;
        } 
      }
      
    • Or an array of tagged template literals:

      class MyElement extends LitElement {
        static get styles() {
          return [ css`:host { display: block; }`, ...];
        }
      }
      

      Using an array of tagged template literals lets you inherit the styles from a LitElement superclass, and add more:

      class MySubElement extends MyElement {
        static get styles() {
          return [
            super.styles,
            css`
              :host(.important) {
                color: red;
              }
            `
          ];
        }
      }
      

Expressions in static styles

Static styles apply to all instances of an element. Any expressions in your CSS are evaluated and included once, then reused for all instances.

To prevent LitElement-based components from evaluating potentially malicious code, the css tag only accepts literal strings. You can nest them like this:

static get styles() {
  const mainColor = css`red`;

  return css`
    :host { 
      color: ${mainColor}; 
    }
  `;
}

However, if you want to inject any variable or non-literal into a css string, you must wrap it with the unsafeCSS function. For example:

import { LitElement, css, unsafeCSS } from 'lit-element';

class MyElement extends LitElement {
  static get styles() {
    const mainColor = 'red';
    
    return css`
      :host { 
        color: ${unsafeCSS(mainColor)};
      }
    `;
  } 
}

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.

Define styles in a style element

We recommend using static styles to style LitElement components. However, in some cases you may want to evaluate and apply styles per instance, rather than to all instances of a LitElement component. One way to do this is to include inline styles in a <style> element in your template, and use your element’s properties in your CSS rules to evaluate styles per instance.

Expressions inside a <style> element won’t update per instance in ShadyCSS. Due to limitations of the ShadyCSS polyfill, you can’t use element properties in CSS rules as the expressions won’t be evaluated.

import {LitElement, property} from 'lit-element';

class MyElement extends LitElement {
  @property() mainColor = 'blue';
  render() {
    return html`
      <style>
        :host {
          color: ${this.mainColor};
        }
      </style>
    `;
  }
}

Define styles in an external stylesheet

We strongly recommend static styles, CSS custom properties, or lit-html’s classMap or styleMap directives if you’re styling non-host shadow root contents.

However, you can load an external stylesheet into a shadow root with a <link> element:

import {LitElement} from 'lit-element';

class MyElement extends LitElement {
  render() {
    return html`
      <link rel="stylesheet" href="./styles.css">
    `;
  }
}

This can be a good way to load CSS generated from tools like SASS/LESS.

There are some important caveats though:

Write CSS styles for a host element and its shadow DOM

In this section:

Write CSS styles for a host element

An element can apply styles to itself with the :host and :host() CSS psuedo-classes used inside the element’s ShadowRoot. The term “host” is used because an element is the host of its own shadow root.

Two best practices for working with custom elements are:

See Custom Element Best Practices for more information.

Write CSS styles for elements in shadow DOM

To style elements in a shadow root, simply use standard CSS selectors.

Since CSS selectors in a shadow root only apply to elements in the shadow root, you don’t need to be defensive against accidentally styling other elements in the page. This means you can generally write much simpler selectors, that are easier to reason about, and faster, than without shadow DOM.

Simple selectors, like *, tagname, id, and class selectors, are fine in a shadow root because they don’t match outside the root:

* {
  color: black;
}

h1 {
  font-size: 4rem;
}

#main {
  padding: 16px;
}

.important {
  color: red;
}

Write CSS styles for slotted children

Use the ::slotted() CSS pseudo-element to select light DOM children that have been included in shadow DOM via the <slot> element.

import { LitElement, html } from 'lit-element';

class MyElement extends LitElement {
  render() {
    return html`
      <style>
        :host([hidden]) { display: none; }
        :host { display: block; }
        ::slotted(*) { font-family: Roboto; }
        ::slotted(span) { color: blue; }
        div ::slotted(*) { color: red; }
      </style>
      <slot></slot>
      <div><slot name="hi"></slot></div>
    `;
  }
}
customElements.define('my-element', MyElement);

Styling options for component consumers

When you use a LitElement component, you can set styles from the main document by using its custom element tag as a selector. For example:

index.html

<style>
  my-element { 
    font-family: Roboto;
    font-size: 20;
    color: blue;
  }
</style>
...
<my-element></my-element>

An element type selector has higher specificity than the :host pseudo-class selector.

Styles set for a host element from outside its shadow DOM will override styles set with the :host or :host() pseudo-class selectors inside shadow DOM. See Inheritance.

Theming

This section describes how to use CSS inheritance and custom CSS properties to:

CSS Inheritance and shadow DOM

Inherited CSS properties like color, font-family, and all CSS custom properties (--*) inherit through shadow root boundaries.

This means that by default an element will share some important styles from its outside context.

Component authors can take advantage of this to style all of a shadow root’s contents by setting inherited properties on the host with the :host CSS pseudo-class:

my-element.js

render() {
  return html`
    <style>
      :host { 
        display: block; 
        font-family: Roboto;
        font-size: 20;
        color: blue;
      }
    </style>
    <p>Inherits font styles</p>
  `;
}

If a host element itself inherits properties from another element, the host’s shadow DOM children will inherit those properties in turn:

  <style>
    div { font-family: Roboto; }
  </style>
  <div>
    <my-element>Will use Roboto font</my-element>
  </div>

A LitElement component can be styled by using its custom element tag as a selector. For example:

index.html

<style>
  my-element { 
    font-family: Roboto;
    font-size: 20;
    color: blue;
  }
</style>
...
<my-element></my-element>

An element type selector has higher specificity than the :host pseudo-class selector.

Styles set for a host element from outside its shadow DOM will override styles set with the :host or :host() pseudo-class selectors inside shadow DOM. For example:

index.html

<style>
  /* Overrides the `color` property of the `:host` styles in my-element.js */
  my-element { 
    color: blue;
  }
</style>
...
<my-element></my-element>

my-element.js

<style>
  :host {
    color: red;
    background-color: aliceblue;
  }
</style>

Custom CSS Properties

Custom properties inherit down the DOM tree, and through shadow root boundaries. You can use this to let your users apply styles and themes to your elements.

For example, the following element sets its background color to a CSS variable that uses the value of the custom property --myBackground if it is available, and uses yellow otherwise:

my-element.js

<style>
  :host {
    display: block;
    background-color: var(--myBackground, yellow);
  }
</style>

The user can now set the custom property --myBackground in their main document in order to style the background of my-element.

index.html

<style>
  my-element {
    --myBackground: rgb(67, 156, 144);
  }
</style>

If the user has an existing app theme, they can easily apply their theme properties to my-element:

<style>
  html {
    --themeColor1: rgb(67, 156, 144);
  }
  my-element {
    --myBackground: var(--themeColor1);
  }
</style>
import { LitElement, html } from 'lit-element';

class MyElement extends LitElement {
  render() {
    return html`
      <style>
        :host([hidden]) { display: none; }
        :host { display: block;
          background-color: var(--myBackground, yellow);
          color: var(--myColor, black);
          padding: var(--myPadding, 8px);
        }
      </style>
      <p>Hello world</p>
    `;
  }
}
customElements.define('my-element', MyElement);

See CSS Custom Properties on MDN for more information.

A simple example theme

index.html

<!DOCTYPE html>
<html>
  <head>
    <script src="/node_modules/@webcomponents/webcomponentsjs/custom-elements-es5-adapter.js"></script>
    <script src="/node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js"></script>
    <title>lit-element code sample</title>
    <style>
      body {
        --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);
      } 

      my-element.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 styles = css`
    :host { 
      display: block;
      color: var(--my-element-text-color); 
      background: var(--my-element-background-color);  
      font-family: var(--my-element-font-family);
    }
    :host([hidden]) {
      display: none;
    }
  `;
  render() {
    return html`
      <div>Hello from my-element</div>
    `;
  }
}
customElements.define('my-element', MyElement);