lit-element vs lit-html
Building Web Components with Lit Architecture
lit-elementlit-htmlSimilar Packages:

Building Web Components with Lit Architecture

lit-element and lit-html are the core libraries that power the Lit project for building Web Components. lit-html is a lightweight rendering engine that uses tagged template literals to update the DOM efficiently. lit-element builds on top of lit-html to provide a base class for Web Components with reactive properties and lifecycle callbacks. Note that as of Lit 2.0, these packages have been unified into a single lit package for new development.

Npm Package Weekly Downloads Trend

3 Years

Github Stars Ranking

Stat Detail

Package
Downloads
Stars
Size
Issues
Publish
License
lit-element021,482124 kB6964 months agoBSD-3-Clause
lit-html021,4821.71 MB6964 months agoBSD-3-Clause

Lit Architecture: lit-element vs lit-html

Both lit-element and lit-html are foundational pieces of the Lit library suite, designed to make building Web Components fast and reliable. While they share the same core rendering engine, they solve different problems in the component stack. It is important to note that modern development should target the unified lit package, but understanding the distinction helps when maintaining older codebases.

🎯 Core Purpose: Rendering Engine vs Component Base

lit-html is strictly a view layer.

  • It renders templates into DOM nodes.
  • It does not manage state or lifecycle events.
  • Best for simple UI updates or custom rendering logic.
// lit-html: Direct rendering
import { html, render } from 'lit-html';

const template = (name) => html`<p>Hello ${name}</p>`;
render(template('World'), document.body);

lit-element is a full Web Component base class.

  • It extends HTMLElement to create custom tags.
  • It includes state management and lifecycle hooks.
  • Best for building reusable, encapsulated components.
// lit-element: Component class
import { LitElement, html } from 'lit-element';

class MyElement extends LitElement {
  render() {
    return html`<p>Hello World</p>`;
  }
}
customElements.define('my-element', MyElement);

🧠 State Management: None vs Reactive Properties

lit-html has no built-in state system.

  • You must pass data manually into template functions.
  • Changes require calling render() again with new data.
  • Good for functional-style UI updates.
// lit-html: Manual data passing
let count = 0;
const update = () => {
  count++;
  render(html`<div>${count}</div>`, container);
};

lit-element has a reactive property system.

  • Define properties using a static getter or decorators.
  • The component re-renders automatically when data changes.
  • Reduces boilerplate for state-driven UIs.
// lit-element: Reactive properties
import { property } from 'lit-element/decorators.js';

class Counter extends LitElement {
  @property({ type: Number }) count = 0;

  render() {
    return html`<div>${this.count}</div>`;
  }
}

🔄 Lifecycle: Manual vs Built-In Hooks

lit-html offers no lifecycle hooks.

  • You manage setup and cleanup outside the render function.
  • You must manually attach event listeners or observers.
  • More control but more code to maintain.
// lit-html: Manual setup
function init() {
  const sub = subscribe(data => {
    render(html`<div>${data}</div>`, container);
  });
  return () => sub.unsubscribe(); // Manual cleanup
}

lit-element provides standard lifecycle methods.

  • Use connectedCallback, updated, or disconnectedCallback.
  • Hooks integrate with the reactive update cycle.
  • Easier to manage side effects like API calls.
// lit-element: Lifecycle hooks
class UserData extends LitElement {
  updated() {
    console.log('Component updated');
  }

  disconnectedCallback() {
    super.disconnectedCallback();
    // Cleanup logic here
  }
}

📦 The Modern Unified Package

Starting with Lit 2.0, the team merged these libraries into one package called lit.

  • You import LitElement and html from 'lit'.
  • This reduces dependency count and simplifies versioning.
  • Legacy packages remain available but are not recommended for new work.
// Modern lit: Unified import
import { LitElement, html } from 'lit';

class ModernElement extends LitElement {
  render() {
    return html`<div>Using unified package</div>`;
  }
}

🤝 Similarities: Shared Ground Between lit-element and lit-html

While their roles differ, both libraries share core technologies and principles.

1. 📝 Tagged Template Literals

  • Both use the html tag function to define templates.
  • Syntax highlighting and linting work similarly in editors.
// lit-html template
const view = html`<div>Content</div>`;

// lit-element template
render() { return html`<div>Content</div>`; }

2. ⚡ Efficient DOM Updates

  • Both use a virtual DOM-like diffing algorithm.
  • Only changed parts of the DOM are updated on re-render.
  • Ensures high performance for dynamic interfaces.
// Both: Efficient binding updates
html`<div>${dynamicValue}</div>`; // Only text node updates

3. 🌐 Web Standards Focus

  • Both rely on native browser features like Custom Elements.
  • No heavy runtime abstraction or custom virtual DOM.
  • Works well with other frameworks and libraries.
// Both: Standard Custom Elements API
customElements.define('my-element', MyClass);

4. 🛡️ Security Defaults

  • Both escape values by default to prevent XSS attacks.
  • Developers must explicitly opt-in for unsafe HTML.
  • Protects applications from common injection vulnerabilities.
// Both: Safe by default
html`<div>${userInput}</div>`; // Escaped automatically

5. 🔌 TypeScript Support

  • Both ship with full TypeScript definitions included.
  • Decorators and properties are strongly typed.
  • Enhances developer experience in large codebases.
// Both: TypeScript decorators
@property({ type: String }) name: string = '';

📊 Summary: Key Similarities

FeatureShared by lit-element and lit-html
Template Syntax📝 Tagged template literals
Rendering⚡ Efficient partial updates
Standards🌐 Native Web Components
Security🛡️ Auto-escaping values
Types🔌 Built-in TypeScript support

🆚 Summary: Key Differences

Featurelit-htmllit-element
Role🎯 Rendering engine only🧱 Full Web Component base
State❌ Manual data passing✅ Reactive properties
Lifecycle❌ None✅ Hooks (updated, connected, etc.)
Usage🖼️ Render to any node🏷️ Define custom elements
Modern Status⚠️ Legacy (use lit)⚠️ Legacy (use lit)

💡 The Big Picture

lit-html is like a paintbrush 🖌️ — it puts pixels on the canvas but doesn't know about the picture structure. Use it for low-level rendering tasks or when you need maximum flexibility without component overhead.

lit-element is like a framed canvas 🖼️ — it provides structure, state, and lifecycle around the rendering. Use it when building reusable UI components that need to manage their own data.

Final Thought: For any new project, skip the decision entirely and use the unified lit package. It combines the best of both libraries into a single, maintained dependency. Reserve lit-element and lit-html specific imports for maintaining older codebases where migration is not yet feasible.

How to Choose: lit-element vs lit-html

  • lit-element:

    Choose lit-element only if you are maintaining a legacy project that relies on separate package imports. For all new Web Components, you should import LitElement from the unified lit package instead. Using the legacy package in new projects adds unnecessary dependency complexity.

  • lit-html:

    Choose lit-html only if you need raw DOM rendering without the overhead of a Web Component class. This is rare in modern Lit development. For most cases, import the html tag function from the unified lit package to ensure compatibility with current tooling and updates.

README for lit-element

LitElement

A simple base class for creating fast, lightweight web components.

Build Status Published on npm Join our Discord Mentioned in Awesome Lit

LitElement is the base class that powers the Lit library for building fast web components.

Most users should import LitElement from the lit package rather than installing and importing from the lit-element package directly.

Documentation

Full documentation is available at lit.dev/docs/components/overview/.

Overview

LitElement is a base class for custom elements that extends the Lit project's core ReactiveElement (from `@lit/reactive-element') base class with lit-html templating. ReactiveElement enhances HTMLElement with reactive properties, additional lifecycle callbacks, convenient inline CSS authoring, and a set of useful class decorators, while lit-html provides fast, declarative HTML templating.

Example

import {LitElement, html, css} from 'lit';
import {customElement, property} from 'lit/decorators.js';

// Registers the element
@customElement('my-element')
export class MyElement extends LitElement {
  // Styles are applied to the shadow root and scoped to this element
  static styles = css`
    span {
      color: green;
    }
  `;

  // Creates a reactive property that triggers rendering
  @property()
  mood = 'great';

  // Render the component's DOM by returning a Lit template
  render() {
    return html`Web Components are <span>${this.mood}</span>!`;
  }
}

Contributing

Please see CONTRIBUTING.md.