Style Components with CSS Stylesheets

To bundle a set of styles with a component, create a stylesheet with the same name as the component in the component’s folder. The stylesheet is automatically applied to the component. If you want to style a component with one or more stylesheets, configure the stylesheets static property.

You can only have one stylesheet in a component’s folder. Stylesheets use standard CSS syntax and you can use most selectors. A stylesheet can import style rules from multiple CSS modules.

In shadow DOM, styles defined in a component’s stylesheet are scoped to the component. This rule allows a component to be reused in different contexts without losing its style. It also prevents a component’s styles from overriding styles in other parts of a page.

Deep Dive: Shadow DOM & CSS in Lightning Web Components

The video discusses CSS styling in synthetic shadow using the format <div c-child_child>, which is how the CSS scope tokens were generated before Winter '24. The previous format and the current format <div lwc-12abcdefg-host> looks visually different but their purpose as CSS scope tokens is the same.

This example demonstrates how the CSS styles defined in a parent component don’t reach into a child. There are two components, c-parent and c-child. Each component contains an <h1> tag. The parent.css stylesheet defines the h1 style as xx-large. When you run the code, the style applies only to the <h1> tag in the parent, not to the <h1> tag in the nested child.

Parent text is extra large. Child text is normal size.

A parent component can style a child component, but it styles it as a single element. A parent can’t reach into a child. Let’s add a c-child selector to parent.css that defines a border around the child component.

The child component has a red box around it.

Now let’s style the c-child component from its own style sheet, child.css.

Before we add a selector to child.css, let’s remove the c-child selector from parent.css to remove the red box. It’s not a good practice to style components from both the component and its parent, because it can be confusing and yield unexpected results. Here is parent.css with the c-child removed.

A component’s stylesheet can reach up and style its own element, which in this example is c-child.

Instead of using a c-child selector, use the :host selector.

Child component's background is yellow.

By targeting the host element with :host, we’ve applied styling to <c-child>, from child.css.

The :host selector accepts an optional list of selectors. To match, the host element must have a class that matches the passed selector. To see how the :host selector works, let’s rewrite our sample code to look slightly more like a real app. We add a <slot> to c-child so we can pass the name of the item on the To Do List.

Let’s style the h1 in the child component, but make it large, which is a bit smaller than the xx-large h1 we defined in the parent component. Let’s also make all list items light gray except the active item, which is light green.

In the parent, let’s add three c-child components and make one active. In a real app, the active component would be the selected item.

To do list with active to do item in light green.

The CSS rules on cascading, specificity, and inheritance apply to shadow DOM.

Cascading refers to the combining of CSS rules in different stylesheets that are applied to an element. For specificity, if you have a <div> in a component with multiple selectors with the same property, the browser uses the property that's defined the latest, or background: red in this example.

To increase the specificity of a selector, use a CSS class or include the element that the selector appears under. ID selectors aren't supported as they are transformed into globally unique values at runtime. In this example, adding the lightning-card element targets the <div> tags and increases the specificity.

Using a CSS class selector is more specific. A <div> tag that uses the .somecolor class selector gets background: blue; instead of the latest definition background:red.

CSS inheritance applies if no cascaded value is found. Some CSS property values like color and font are inherited from parent elements. Consider this HTML markup in a component.

Given this CSS class selector, "Some text" is rendered in red because the color property is inherited from the <div> parent element.

Not all properties can inherit colors from a parent element. To check if the CSS property is inherited, review the W3C or MDN documentation. If the property is inherited, the styles of the parent applies to the children. If it's not an inherited property, such as the border property, the property is set to the initial value.

Shadow DOM prevents cascaded styles from affecting your component, but the same isn't true with inherited styles. Cascaded styles don't traverse the shadow boundary while inherited values traverse the shadow boundary.

In this example, the text in the c-child component is red although c-child renders in shadow DOM. Since color is an inherited property, it's inherited through the shadow DOM as well.

Additionally, CSS custom properties also traverse shadow boundaries.

The CSS scoping matches the CSS Scoping Module Level 1 standard, with a few exceptions.

  • No support for the :host-context() pseudo-class function.
  • No support for the ::part pseudo-element.
  • No support for ID selectors in CSS. Make sure that id values are unique within your HTML template. When the template is rendered, id values may be transformed into globally unique values. If you use an ID selector in CSS, it won’t match the transformed ID.
  • LWC doesn’t reflect a component’s custom public properties into their corresponding HTML attributes. To give identity to a child element for styling, use a class attribute or a data-* attribute.

Scoped CSS affects performance, so use it with care. Each selector chain is scoped, and each compound expression passed to :host() is spread into multiple selectors. This transformation increases the size and complexity of the generated CSS. These increases mean more bits on the wire, longer parsing time, and longer style recalculation time.

To ensure CSS encapsulation, each element has an extra attribute, which also increases rendering time. For example, the <c-parent> element has a c-parent_parent-host attribute.

To customize a component with one or more stylesheets, add the stylesheets static property to the LightningElement constructor. This property accepts an array of stylesheets, and its default value is an empty array. You can set the stylesheets property for light DOM and shadow DOM components.

For example, to inject the header-styles.css and button-styles.css stylesheets into myComponent, configure the stylesheets static property in myComponent.js.

The first stylesheet the LWC engine injects is myComponent.css, since it's implicitly associated with the component’s template. Then the engine loads all the stylesheets associated with the stylesheets property in the order that they’re listed inside the array. Based on this configuration of stylesheets, myComponent loads its stylesheets in the following order: myComponent.css, header-styles.css, and button-styles.css.

The LWC engine caches the stylesheets array for the lifetime of the application during the component class definition. If you modify stylesheets after the component’s code is evaluated, it won’t affect the injected stylesheets.

A subclass component doesn’t automatically inherit stylesheets from a superclass component. If you want to extend stylesheets from a superclass component to a subclass component, use super.stylesheets to manually merge the superclass stylesheets with the stylesheets for the subclass component.

See Also