Lit is better than React: Signals in Lit
Source: Dev.to
Lit is generally faster in raw benchmarks because it avoids the “diffing tax” of a virtual DOM. React excels at developer ergonomics and has a large ecosystem, which is why it remains more popular. Below is a concise comparison based on the Krausest Benchmark and other observations.
Comparison Overview
| Category | Lit | React (v19+) | Winner |
|---|---|---|---|
| Duration (Weighted Mean) | ~1.05 – 1.15 | ~1.6 – 1.8 | Lit |
| Startup / Boot Time | Fastest | Moderate | Lit |
| Swap 2 Rows | Excellent | Slow (VDOM overhead) | Lit |
| Memory Usage | Minimal | High (~10 MB+) | Lit |
- Performance: Lit avoids building a virtual DOM, resulting in lower CPU usage and memory footprint.
- Bundle Size: Lit’s runtime is ~5 KB (native browser APIs) versus ~30 KB+ for React.
- Use Cases: Lit shines in design systems, micro‑frontends, and performance‑critical UIs, while React’s extensive ecosystem makes it a go‑to for large, complex applications.
Why I Prefer Lit
- Standards‑First: Lit stays close to native web standards, which tends to yield better performance because it leverages the platform directly.
- Developer Experience: While vanilla Web Components can be cumbersome, Lit provides a lightweight abstraction that makes them pleasant to work with.
- Learning Resources: I have a beginner‑level YouTube video that demonstrates creating a dark mode with Lit (search “Lit dark mode tutorial”).
Issues with React’s Virtual DOM
React’s virtual DOM introduces three main drawbacks, which even the React team acknowledges:
- Re‑rendering Overhead – Every state change triggers a diff of the entire virtual tree, leading to unnecessary work for large apps.
- Bundle Size Bloat – The diff engine adds ~30 KB+ to the bundle, inflating download size.
- Memory Usage – Keeping a copy of the UI in memory increases RAM consumption, especially for complex interfaces.
React attempts to mitigate these problems with the React compiler, but it remains a band‑aid because it still relies on the virtual DOM. A more fundamental solution is to eliminate the virtual DOM altogether.
Signals – A New Approach
Signals provide a direct, graph‑based link between data and UI. When a signal’s value changes, the UI updates automatically without any virtual DOM diffing. Several libraries (e.g., SolidJS) already adopt signals, and there is an active proposal to make them a standard JavaScript feature.
Lit now supports signals through the experimental @lit-labs/signals package. While still experimental, it demonstrates how signals can be integrated into Lit components.
Example: Counter with Lit and Signals
import { LitElement, html } from 'lit';
import { customElement } from 'lit/decorators.js';
import { signal, watch, SignalWatcher } from '@lit-labs/signals';
// Define a signal outside the class
const count = signal(0);
@customElement('my-element')
export class MyElement extends SignalWatcher(LitElement) {
render() {
// Subscribe to the signal with `watch`
return html`
Count is ${watch(count)}
`;
}
private _onClick() {
// Update the signal
count.set(count.get() + 1);
}
}
- The
SignalWatchermixin enables automatic re‑rendering whencountchanges. - No property decorators are needed; the signal itself holds the state.
- For more details, see the @lit-labs/signals package documentation.
Conclusion
If you’re building micro‑frontends, design systems, or content‑driven apps with an island architecture, Lit’s standards‑based approach and its emerging signal support make it a compelling alternative to React. While React remains popular for its ecosystem and developer ergonomics, Lit offers superior performance, smaller bundle sizes, and lower memory usage—especially when combined with signals.