Skip to content

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.