Skip to content

Lit Element — Complete Guide

DodaTech Updated 2026-06-28 2 min read

In this tutorial, you will learn about Lit Element. We cover key concepts, practical examples, and best practices to help you master this topic.

Lit is a lightweight library for building Web Components with reactive properties, declarative templates, and efficient re-rendering using lit-html.

What You'll Learn

  • How to define Lit components
  • How to use reactive properties
  • How Lit templates update efficiently
  • How to compose Lit components

Why It Matters

Vanilla Web Components require manual rendering, property Reflection, and event handling. Lit automates these patterns, making component development faster and less error-prone.

flowchart LR
  A[Lit Component] --> B[Reactive Properties]
  A --> C[Lit-html Templates]
  A --> D[Shadow DOM]
  B --> E[Auto attribute reflection]
  B --> F[Re-render on change]
  C --> G[Efficient DOM updates]

Basic Lit Component

import { LitElement, html, css } from 'lit';

class MyElement extends LitElement {
    static properties = {
        name: { type: String },
        count: { type: Number },
        active: { type: Boolean, reflect: true }
    };

    static styles = css`
        :host { display: block; padding: 16px; }
        .highlight { color: blue; }
    `;

    constructor() {
        super();
        this.name = 'World';
        this.count = 0;
        this.active = false;
    }

    render() {
        return html`
            <h1>Hello, ${this.name}!</h1>
            <p>Count: ${this.count}</p>
            <button @click=${this._increment}>+1</button>
            <p class=${this.active ? 'highlight' : ''}>Status: ${this.active}</p>
        `;
    }

    _increment() {
        this.count++;
    }
}
customElements.define('my-element', MyElement);

Reactive Properties

import { LitElement, html } from 'lit';

class UserCard extends LitElement {
    static properties = {
        userId: { type: Number },
        user: { state: true }, // Internal state, not reflected
        loading: { type: Boolean }
    };

    constructor() {
        super();
        this.userId = 0;
        this.user = null;
        this.loading = false;
    }

    willUpdate(changedProps) {
        if (changedProps.has('userId')) {
            this._fetchUser();
        }
    }

    async _fetchUser() {
        this.loading = true;
        const response = await fetch(`/api/users/${this.userId}`);
        this.user = await response.json();
        this.loading = false;
    }

    render() {
        if (this.loading) return html`<p>Loading...</p>`;
        if (!this.user) return html`<p>No user</p>`;
        return html`
            <h2>${this.user.name}</h2>
            <p>${this.user.email}</p>
        `;
    }
}
customElements.define('user-card', UserCard);

Common Mistakes

  1. Forgetting to import LitElement from 'lit'
  2. Using state: true for properties that should trigger re-render but not reflect
  3. Modifying arrays/objects in place (Lit needs new references)

Practice Questions

  1. What does reflect: true do in a property definition? Reflects the property value back to the HTML attribute.
  2. How does Lit detect property changes? By checking !== comparison on set.

Mini Project

Convert a vanilla Web Component to Lit. Choose a component from a previous lesson and rewrite it using Lit's reactive properties, lit-html templates, and scoped styles.

What's Next

Lesson 20: Stencil

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro