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.
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.
lit-html is strictly a view layer.
// 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.
HTMLElement to create custom tags.// 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);
lit-html has no built-in state system.
render() again with new data.// lit-html: Manual data passing
let count = 0;
const update = () => {
count++;
render(html`<div>${count}</div>`, container);
};
lit-element has a reactive property system.
// 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>`;
}
}
lit-html offers no lifecycle hooks.
// 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.
connectedCallback, updated, or disconnectedCallback.// lit-element: Lifecycle hooks
class UserData extends LitElement {
updated() {
console.log('Component updated');
}
disconnectedCallback() {
super.disconnectedCallback();
// Cleanup logic here
}
}
Starting with Lit 2.0, the team merged these libraries into one package called lit.
LitElement and html from 'lit'.// Modern lit: Unified import
import { LitElement, html } from 'lit';
class ModernElement extends LitElement {
render() {
return html`<div>Using unified package</div>`;
}
}
While their roles differ, both libraries share core technologies and principles.
html tag function to define templates.// lit-html template
const view = html`<div>Content</div>`;
// lit-element template
render() { return html`<div>Content</div>`; }
// Both: Efficient binding updates
html`<div>${dynamicValue}</div>`; // Only text node updates
// Both: Standard Custom Elements API
customElements.define('my-element', MyClass);
// Both: Safe by default
html`<div>${userInput}</div>`; // Escaped automatically
// Both: TypeScript decorators
@property({ type: String }) name: string = '';
| Feature | Shared 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 |
| Feature | lit-html | lit-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) |
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.
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.
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.
A simple base class for creating fast, lightweight web components.
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.
Full documentation is available at lit.dev/docs/components/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.
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>!`;
}
}
Please see CONTRIBUTING.md.