Add a template to your component to define internal DOM to implement your component.
To encapsulate the templated DOM LitElement uses shadow DOM. Shadow DOM provides three benefits:
- DOM scoping. DOM APIs like
document.querySelectorwon't find elements in the component's shadow DOM, so it's harder for global scripts to accidentally break your component.
- Style scoping. You can write encapsulated styles for your shadow DOM that don't affect the rest of the DOM tree.
- Composition. The component's shadow DOM (managed by the component) is separate from the component's children. You can choose how children are rendered in your templated DOM. Component users can add and remove children using standard DOM APIs without accidentally breaking anything in your shadow DOM.
Where native shadow DOM isn't available, LitElement uses the Shady CSS polyfill.
Define and render a templatePermalink to “Define and render a template”
To define a template for a LitElement component, write a
render function for your element class:
Tag your template literal with the
rendermethod can return anything that lit-html can render. Typically, it returns a single
TemplateResultobject (the same type returned by the
LitElement uses lit-html templates; this page summarizes the features of lit-html templates, for more details, see Writing templates and the Template syntax reference in the lit-html documentation.
Design a performant templatePermalink to “Design a performant template”
LitElement renders and re-renders asynchronously, updating in response to batched property changes (see Element update lifecycle for more information).
During an update, only the parts of the DOM that change are re-rendered. To get the performance benefits of this model, you should design your element's template as a pure function of its properties.
To do this, make sure the
- Does not change the element's state.
- Does not have any side effects.
- Only depends on the element's properties.
- Returns the same result when given the same property values.
Also, avoid making DOM updates outside of
render. Instead, express the element's template as a function of its state, and capture its state in properties.
The following code uses inefficient DOM manipulation:
We can improve the template by declaring the message as a property, and binding the property into the template. Declaring a property tells your component to re-render its template when the property changes.
The following sections discuss different types of property bindings. See Properties for information on declaring properties.
Use properties, loops, and conditionals in a templatePermalink to “Use properties, loops, and conditionals in a template”
When defining your element's template, you can bind the element's properties to the template; the template is re-rendered whenever the properties change.
PropertiesPermalink to “Properties”
To add a property value to a template, insert it with
LoopsPermalink to “Loops”
Iterate over an array:
repeat directive. In most cases,
Array.map is the most efficient way to create a repeating template. In some cases, you may want to consider lit-html's
repeat directive. In particular, if the repeated elements are stateful, or very expensive to regenerate. For more information, see Repeating templates with the repeat directive in the lit-html docs.
ConditionalsPermalink to “Conditionals”
Render based on a Boolean condition:
ExamplesPermalink to “Examples”
Bind properties to templated elementsPermalink to “Bind properties to templated elements”
- Text content:
- Boolean attribute:
- Event handler:
Data bindings are always one-way (parent to child). To share data from a child element to its parent, fire an event and capture the relevant data in the
Bind to text contentPermalink to “Bind to text content”
prop1 to text content:
Bind to an attributePermalink to “Bind to an attribute”
prop2 to an attribute:
Attribute values are always strings, so an attribute binding should return a value that can be converted into a string.
Bind to a boolean attributePermalink to “Bind to a boolean attribute”
prop3 to a boolean attribute:
Boolean attributes are added if the expression evaluates to a truthy value, and removed if it evaluates to a falsy value.
Bind to a propertyPermalink to “Bind to a property”
prop4 to a property:
Bind to an event handlerPermalink to “Bind to an event handler”
clickHandler to a
The default event context for
@event expressions is
this, so there is no need to bind the handler function.
ExamplesPermalink to “Examples”
Render children with the slot elementPermalink to “Render children with the slot element”
Your component may accept children (like a
<ul> element can have
By default, if an element has a shadow tree, its children don't render at all.
To render children, your template needs to include one or more
<slot> elements, which act as placeholders for child nodes.
Finding slotted children. If your component needs information about its slotted children, see Accessing slotted children.
Use the slot elementPermalink to “Use the slot element”
To render an element's children, create a
<slot> for them in the element's template. For example:
Children will now render in the
The children aren't moved in the DOM tree, but they're rendered as if they were children of the
Arbitrarily many children can populate a single slot:
Use named slotsPermalink to “Use named slots”
To assign a child to a specific slot, ensure that the child's
slot attribute matches the slot's
Named slots only accept children with a matching
<slot name="one"></slot>only accepts children with the attribute
Children with a
slotattribute will only be rendered in a slot with a matching
<p slot="one">...</p>will only be placed in
id, to select slots.
Note that a
id attribute has no effect!
Compose a template from other templatesPermalink to “Compose a template from other templates”
You can compose LitElement templates from other LitElement templates. In the following example, we compose a template for an element called
<my-page> from smaller templates for the page's header, footer, and main content:
You can also compose templates by importing other elements and using them in your template:
Specify the render rootPermalink to “Specify the render root”
The node into which your component's template will render is called its render root.
By default, LitElement creates an open
shadowRoot and renders inside it, producing the following DOM structure:
To customize a component's render root, implement
createRenderRoot and return the node you want the template to render into.
For example, to render the template into the main DOM tree as your element's children:
createRenderRoot and return
Template syntax cheat sheetPermalink to “Template syntax cheat sheet”
RenderPermalink to “Render”
Properties, loops, conditionalsPermalink to “Properties, loops, conditionals”
Data bindingsPermalink to “Data bindings”
CompositionPermalink to “Composition”
SlotsPermalink to “Slots”
Using other lit-html featuresPermalink to “Using other lit-html features”
Since LitElement uses the lit-html
html tag function to define templates you can take advantage of the entire lit-html feature set for writing your templates. This includes lit-html directives, special functions that customize the way lit-html renders a binding.
To import features directly from lit-html, your project should add lit-html as a direct dependency. We recommend using the widest practical version range for lit-html, to minimize the chance of npm installing two different versions of lit-html:
Import and use a lit-html directivePermalink to “Import and use a lit-html directive”
You can import and use a lit-html directive and use it as shown in the lit-html documentation.
For a list of directives supplied with lit-html, see Built-in directives in the Template syntax reference.
Accessing nodes in the shadow DOMPermalink to “Accessing nodes in the shadow DOM”
render() method result is usually rendered into shadow DOM, so the nodes are not direct children of the component. Use
this.shadowRoot.querySelectorAll() to find nodes in the shadow DOM.
You can query the templated DOM after its initial render (for example, in
firstUpdated), or use a getter pattern, like this:
LitElement supplies a set of decorators that provide a shorthand way of defining getters like this.
- Element.querySelector() on MDN.
- Element.querySelectorAll() on MDN.
@query, @queryAll, and @queryAsync decoratorsPermalink to “@query, @queryAll, and @queryAsync decorators”
@queryAsync decorators all provide a convenient way to access nodes in the component's shadow root.
@query decorator modifies a class property, turning it into a getter that returns a node from the render root. The optional second argument is a cache flag which when true performs the DOM query only once and caches the result. This can be used as a performance optimization in cases when the node being queried is not expected to change.
This decorator is equivalent to:
shadowRoot and renderRoot. The
renderRoot property identifies the container that the template is rendered into. By default, this is the component's
shadowRoot. The decorators use
renderRoot, so they should work correctly even if you override
createRenderRoot as described in Specify the render root
@queryAll decorator is identical to
query except that it returns all matching nodes, instead of a single node. It's the equivalent of calling
divs would return both
<div> elements in the template. For TypeScript, the typing of a
@queryAll property is
NodeListOf<HTMLElement>. If you know exactly what kind of nodes you'll retrieve, the typing can be more specific:
The exclamation point (
buttons is TypeScript's non-null assertion operator. It tells the compiler to treat
buttons as always being defined, never
@queryAsync works like
@query, except that instead of returning a node directly, it returns a
Promise that resolves to that node. Code can use this instead of waiting for the
This is useful, for example, if the node returned by
@queryAsync can change as a result of another property change.
Accessing slotted childrenPermalink to “Accessing slotted children”
To access children assigned to slots in your shadow root, you can use the standard
slot.assignedNodes method and the
For example, you can create a getter to access assigned nodes for a particular slot:
You can also use the
slotchange event to take action when the assigned nodes change. The following example extracts the text content of all of the slotted children.
- HTMLSlotElement on MDN.
@queryAssignedNodes decoratorPermalink to “@queryAssignedNodes decorator”
@queryAssignedNodes decorator converts a class property into a getter that returns all of the assigned nodes for a given slot in the component's shadow tree. The optional second boolean argument when true flattens the assigned nodes, meaning any assigned nodes that are slot elements are replaced with their assigned nodes. The optional third argument is a css selector which filters the results to matching elements.
The first example above is equivalent to the following code:
For TypeScript, the typing of a
queryAssignedNodes property is
ResourcesPermalink to “Resources”
For more information on shadow DOM:
- Shadow DOM v1: Self-Contained Web Components on Web Fundamentals.
- Using shadow DOM on MDN.
For more information on lit-html templates: