To bundle styles with a component, create a style sheet in the component’s folder. The style sheet must have the same name as the component. The style sheet is applied to the component automatically.
- Web Components Dynamic Slots No Deposit
- Web Components Dynamic Slots Games
- Web Components Dynamic Slots Software
- Web Components Dynamic Slots App
Each component can have only one style sheet. Components can’t share style sheets. Style sheets use standard CSS syntax and you can use most selectors.
Styles defined in a component’s style sheet 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.
# CSS Scoping Examples
Some browsers are still in the process of updating to support the standards for Web Components. In the mean time, polyfills simulate the missing browser capabilities as closely as possible. The HTML slot tag shifts the emphasis from component developer to component consumer by allowing anyone to add fresh content to a standard web component. Custom Elements and Templates A custom. Dynamic Layouts implements dynamically placed widgets within running applications. The widget placement depends on whether Horizontal or Vertical is chosen. For more information, visit the Layout Management page. This article explains how you can use the template and slot elements to create a flexible template that can then be used to populate the shadow DOM of a web component. MDN will be in maintenance mode, Monday December 14, from 7:00 AM until no later than 5:00 PM Pacific Time (in UTC, Monday December 14, 3:00 PM until Tuesday December 15, 1:00 AM). Web Components are generally available in all of the major browsers with the exception of Microsoft Edge and Internet Explorer 11, but polyfills exist to fill in those gaps. Referring to any of these as Web Components is technically accurate because the term itself is a bit overloaded.
Important
Before we go further, we need to understand naming. A component's folder and file names are camel case, myComponent
, myComponent.html
, and myComponent.css
. In HTML markup, camelCase maps to kebab-case. When a component renders, the <template>
tag is replaced with <namespace-component-name>
. Note that the tag includes the component's namespace. For example, a component with the template myComponent.html
in the example
namespace renders as <example-my-component>
. For more information about naming, see Component Bundles.
This example demonstrates how the CSS styles defined in a parent component don’t reach into a child.
There are two components cssParent
and cssChild
. Each component contains text in a <p>
tag. The cssParent.css
style sheet defines the p
style as xx-large
. The style applies only to the <p>
tag in the parent, not to the <p>
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 the DOM of a child. In the playground, add an example-css-child
selector to cssParent.css
that defines the background of the child component.
Tip
To access cssParent.css
in the playground, scroll to the right in the left pane header and click the filename.
In a new playground, let’s style the example-css-child
component from its own style sheet, cssChild.css
.
A component’s style sheet can reach up and style its own element. Instead of using a example-css-child
selector, use the :host
selector.
Uncomment this code in cssChild.css
. By targeting the host element with :host
, we apply styling to <example-css-child>
, from cssChild.css
.
Note
The cssParent.css
file in this playground doesn't include the example-css-child
selector. 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.
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, in a new playground, let’s rewrite our sample code to look slightly more like a real app.
Style the p
in the child component x-large
, which is just a notch smaller than the p
in the parent component. Make each item whitesmoke
except the active item, which is thistle
.
Right now, the child component contains just a static title, To Do Item. Add a <slot>
to cssChild.html
so the parent component can pass to do item text.
In the parent, add three example-css-child
components and make one active. In a real app, the active component would be the selected item. Because example-css-child
contains a <slot>
, we can pass text for each to do item.
For more information about <slot>
, see Pass Markup into Slots.
Web Components Dynamic Slots No Deposit
# Share CSS Style Rules
To share CSS style rules, create a module that contains only a CSS file. Import the module into the CSS file of any Lightning web component you want to style.You can import style rules from multiple CSS modules. The imported style rules are applied to the template just like non-imported style rules. Lightning Web Components supports the CSS cascade algorithm.
Create a Lightning web component that contains only a single CSS file. This component is your CSS module.
Important
Just like with any Lightning web component, the folder name and the filename must be identical.
Import the module into the CSS file of a Lightning web component.
Imported style rules are applied to the template just like non-imported style rules. All style rules cascade. In the cssSharing.html
template, the text in the <h1>
tag uses the style defined in cssLibrary.css
.
For more information about @import
, see MDN web docs: @import. MDN lists two syntaxes: @import url
and @import url list-of-media-queries
. LWC doesn’t honor the list-of-media-queries
.
# CSS Support and Performance Impact
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
::slotted
pseudo-element. - No support for ID selectors in CSS or JavaScript.
Important
LWC uses id
values for accessibility only. When the template is rendered, id
values are transformed into globally unique values. Don't use ID selectors in JavaScript or in CSS. If you do, the selector won’t match the transformed ID and you get an error.
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 <example-parent>
element has a example-parent_parent-host
attribute.
← ES ModulesComposition →
I've blogged about a few of the behaviours of Lightning Web Components, but the proof is really in building useful bits. What happens when you actually try to make a re-usable component?
For our example, we'll rebuild 'ui:message'. A now (seemingly) defunct base component that would render a message in a box that is coloured based on the 'severity' of the message being shown. In the original it could be set to 'closable', although we're going to ignore that and focus on just the rendering of it.
In a Lightning component we would use it like this:
Original usage - Lightning Component
Ideally, the version we will create, would be used like this:
Desired usage
Looks pretty straightforward, and actually - it is. Just as long as we know about a few simple concepts.
Before we go into them, let's see what a working example could look like:
Javascript component
HTML Template
OK then, let's pick a few of these bits apart, and hopefully we'll explain a few little behaviours along the way.
First up, let's take a look at the '@api' declarations.
@api
The @api property lines are pretty simple to understand - they define that 'title' and 'severity' are publicly available properties of the component. In the context of Lightning Web Components, public and private mean 'available outside of the component, and invisible to the outside of the component'. It's tempting to think that this is to do with the scope of the Javascript, but it's not.
That is, every property of the Javascript component is available to be referenced in the HTML template - whether it is 'public' or 'private'. One way of thinking about it is that the HTML template forms part of the component, and so it can see private properties.
Another (probably more accurate) way of thinking about it is that the template is processed by the Javascript component (that code it's immediately obvious, but it's almost certainly in LightningComponent - which this class extends), and the Javascript can see its own properties, so the private ones are available.
However, other components (like ones that include this in their templates) can only see public properties. @api is how you make them public. Doing so means that they are available as attributes on the tag you use to include the component (hence <c-message... is possible)
Not only that, but every @api decorated property is also 'reactive'. That is, whenever its value changes the component is re-rendered. The documentation is pretty clear on that point - and is presented as a fundamental property of a public property:
Public PropertiesTo expose a public property, decorate it with @api. Public properties define the API for a component. An owner component that uses the component in its markup can access the component’s public properties. Public properties are reactive. If the value of a reactive property changes, the component’s template rerenders any content that references the property.
Web Components Dynamic Slots Games
Why would a public property be reactive?
Put simply, if we change the value of one of those properties in a parent component, we want the component to re-render - and it's pretty much guaranteed that we ALWAYS want the component to re-render.
For example, we may do the following:
When the value of 'title' or 'severity' changes, we would always want the message box to re-render to show our new values. And so the framework takes care of that and makes EVERY public property of the component reactive
So that takes care of the attributes we need to pass in, what about the content?
Slots
Lightning Components had facets. And they weren't intuitive. I mean they weren't complex, but they weren't in keeping with HTML - they always felt unnatural - especially in the simplest of cases.
Lightning Web Components fixes that, with slots. And in the simple case they are trivial. The documentation isn't long, and doesn't need to be.
All we need to do, in this simple case, is add <slot></slot> into our component, and the body of any tag that instantiates the component will be rendered in that slot.
Now something that's missing from the documentation, which is a fairly obvious behaviour once you see it in action, is that slots are effectively reactive.
That is, if you change the content of the tag, that content is immediately reflected in the component's rendered output.
So, in our example:
Web Components Dynamic Slots Software
Whenever the value of 'errorMessages' changes, the slot inside the 'message' component is re-rendered to include the new content.
I admit, I had assumed that this would be the case, but I didn't immediately realise that it was an assumption. So I thought it was worth calling out
Getters
The final part of the example that I want to explain is the use of the 'getter':
What we're doing here is building a list of CSS classes for a node in the component that includes one of the passed in attributes plus a standard class that must be applied
The use of the getter illustrates an important difference between the behaviour of the templates in Lightning Components (LC) and Lightning Web Components (LWC), as well a reminder of the behaviour of properties.
That is, in LC we could have done the following in our template:
In LC, our replacements could include expressions, so we could build up strings in the template. In LWC, we can't do this, we can only reference properties or getters.
Not only that, but we can't build up the strings in the attribute assignment.
I.E. We can't do this:
In LWC we don't assign properties to attributes in this way, the framework takes care of the wrapping in double quotes, escaping the strings, and other such things, so we can only assign the property, and that's it.
I.E. This is what is allowed:
So, if we want to assign more than just the value of 'severity' to the class attribute, we need to build that string up outside of the template.
Your first reaction might be - OK, we can create a trackable property to store it, right?
But this doesn't work. You'll end up with the classes property defined as 'undefined uiMessage', and it won't change. Why is that?
Well, it's tempting to think that 'track' and 'api' mean that Javascript will re-run when things change, but that's not what they do - nor what the documentation says they'll do
Web Components Dynamic Slots App
Rather, if a property is reactive it means that the component will be re-rendered when the property changes. That says nothing about running Javascript.
So when we look at the above, what happens is the property 'classes' is set when the Javascript object is constructed. At this point the property 'severity' is undefined. When the 'severity' is updated via the attribute, the component is re-rendered and the 'classes' property is re-injected into the template, but the Javascript that sets the classes property is not re-run - that is only executed when the object is instantiated.
So, instead of setting the 'classes' property directly, we set up a getter for it:
Javascript component
Now, when the 'severity' property changes, the 'classes' property is re-injected. In order to get the value for 'classes', the getter is executed - this is the only way the property can be retrieved. In doing so, the string concatenation is re-evaluated and the new value is retrieved.
Summary
None of the concepts here are particularly difficult, or really that earth shattering, but building even the simplest of re-usable components starts to shed some light on what the parts do any why.
The framework has been very thoughtfully put together, and some of the techniques will be different to what people are used to, having cut their Javascript teeth with Lightning Components, but the changes are for very good reasons. An example like this really shows how those changes make for simple components.