Lit Directives
This lesson explains Lit directives and how they extend templates with specialized behavior for classes, styles, lists, conditional attributes, and custom DOM updates.
What Are Lit Directives?
Lit directives are special functions used inside
html templates to control how parts of the DOM are
created or updated. They extend Lit's template system beyond
simple value bindings.
Directives are useful for dynamic classes, inline styles, efficient
list rendering, conditional attributes, and custom update logic in
Lit components.
| Concept | Description |
| Directive | Special template helper in Lit |
| Built-in Directives | classMap, styleMap, repeat |
| Attribute Directives | Control attributes or properties on elements |
| Custom Directives | User-defined update behavior |
| Used In | html`...` templates |
| Main Benefit | Cleaner and more efficient templates |
Basic Directive Example
import { LitElement, html } from "lit";
import { classMap } from "lit/directives/class-map.js";
import { customElement, property } from "lit/decorators.js";
@customElement("status-badge")
class StatusBadge extends LitElement {
@property()
variant = "info";
@property({ type: Boolean })
active = false;
render() {
return html`
<span
class="${classMap({
badge: true,
active: this.active,
[`badge-${this.variant}`]: true
})}"
>
<slot></slot>
</span>
`;
}
}
The classMap directive applies CSS classes based on
an object, which is cleaner than building class strings manually.
Common Built-in Directives
| Directive | Purpose |
classMap | Apply multiple CSS classes conditionally |
styleMap | Apply inline styles from an object |
repeat | Render lists efficiently with keys |
ifDefined | Set attribute only when value is defined |
live | Sync form values after user input |
unsafeHTML | Render trusted HTML strings |
classMap Directive
import { classMap } from "lit/directives/class-map.js";
render() {
return html`
<button
class="${classMap({
btn: true,
primary: this.variant === "primary",
disabled: this.disabled
})}"
>
${this.label}
</button>
`;
}
classMap is ideal for variant-based styling and
boolean class toggles in Lit components.
styleMap Directive
import { styleMap } from "lit/directives/style-map.js";
render() {
return html`
<div
style="${styleMap({
backgroundColor: this.bgColor,
color: this.textColor,
padding: "1rem"
})}"
>
Themed content
</div>
`;
}
Use styleMap when inline styles depend on dynamic
component state.
repeat Directive
import { repeat } from "lit/directives/repeat.js";
render() {
return html`
<ul>
${repeat(
this.items,
(item) => item.id,
(item) => html`
<li>${item.label}</li>
`
)}
</ul>
`;
}
repeat is often better than
items.map() for lists because it uses keys to update
DOM nodes more efficiently when items change order.
ifDefined Directive
import { ifDefined } from "lit/directives/if-defined.js";
render() {
return html`
<input
type="text"
placeholder="Search"
aria-label="${ifDefined(this.ariaLabel)}"
/>
`;
}
ifDefined sets an attribute only when the value is
defined, which helps avoid empty or unwanted attributes.
live Directive
import { live } from "lit/directives/live.js";
render() {
return html`
<input
type="text"
.value="${live(this.query)}"
@input="${this.handleInput}"
/>
`;
}
The live directive helps keep controlled form values
in sync when Lit re-renders after user input.
repeat vs map
| Feature | repeat | map() |
| Keyed updates | Yes | No built-in key support |
| Best for | Dynamic lists that reorder or change | Simple static lists |
| Performance | Better for changing collections | Fine for small/simple lists |
Custom Directives
import { directive, Directive } from "lit/directive.js";
class FocusDirective extends Directive {
update(part) {
const element = part.element;
if (this.shouldFocus) {
element.focus();
}
return this.render();
}
}
const focus = directive(FocusDirective);
render() {
return html`
<button type="button" ${focus(this.autoFocus)}>
Save
</button>
`;
}
Custom directives let you package reusable DOM behavior and use it
directly inside Lit templates.
unsafeHTML Directive
import { unsafeHTML } from "lit/directives/unsafe-html.js";
render() {
return html`
<article>
${unsafeHTML(this.trustedHtml)}
</article>
`;
}
Use unsafeHTML only with trusted content. Lit escapes
values by default, and this directive bypasses that protection.
When to Use Lit Directives
- You need conditional CSS classes or inline styles.
- You render dynamic lists that reorder or update often.
- You want cleaner templates than manual string building.
- You need conditional attributes like
aria-label. - You are building controlled form inputs in Lit.
- You want reusable custom DOM behavior in templates.
Common Directive Use Cases
- Variant styling with
classMap on buttons and badges. - Theme colors with
styleMap. - Menus, tables, and lists with
repeat. - Optional accessibility attributes with
ifDefined. - Search inputs and form fields with
live. - Custom focus, tooltip, or animation behavior.
Lit Directive Best Practices
- Prefer built-in directives before writing custom ones.
- Use
repeat with stable keys for dynamic lists. - Use
classMap and styleMap for readable templates. - Avoid
unsafeHTML unless content is fully trusted. - Keep custom directives focused on one behavior.
- Import directives from their specific Lit module paths.
- Combine directives with clean
render() structure.
Common Directive Mistakes
- Using
map() for large reordering lists instead of repeat. - Building class strings manually when
classMap is clearer. - Using
unsafeHTML with untrusted user content. - Forgetting to import directives from
lit/directives/.... - Creating custom directives for simple one-line template logic.
- Not providing stable keys in
repeat. - Overusing directives and making templates harder to read.
Key Takeaways
- Lit directives extend templates with specialized update behavior.
classMap, styleMap, and repeat are the most common built-ins. ifDefined and live solve common attribute and form cases. - Custom directives let you reuse advanced DOM behavior.
- Directives make Lit templates cleaner, safer, and more efficient.
Pro Tip
Reach for classMap, styleMap, and
repeat first. They solve most real-world Lit template
needs before you need to write a custom directive.