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.
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.
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.
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.
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.
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 adata-*
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