Why Lit Is So Good
Wouldn’t it be nice to have the benefits of modern UI frameworks but without the frameworks? Well, Lit gives you pretty much that. It’s a library wrapping around native JavaScript web components, allowing reactive, declarative UI development without any overhead.
The Selling Point
Since Lit is just native JS code, it runs anywhere. You can drop a Lit component into a React app and it will work. You can drop it into an Angular app and it will still work. This makes it ideal for things like component libraries that will be used by various projects built on different UI frameworks. No build needed either. You simply add your vanilla JS code, and an HTML tag to render it, and that’s it.
Example
To demonstrate web components in action, I’ve made this counter with a few lines of inline JS (it won’t be visible if your JS is disabled).
I basically just declared a NativeCounter class extending HTMLElement and registered it to the DOM as native-counter, all inside MDX. Using Lit for this small example would’ve been overkill since it would require the client to download the entire Lit distributable from a CDN, but Lit operates on the same principle as this example so it proves the concept.
Full counter code below:
class NativeCounter extends HTMLElement {
constructor() {
super();
this.count = 0;
const shadow = this.attachShadow({ mode: 'open' });
this.button = document.createElement('button');
this.button.textContent = `Count: ${this.count}`;
this.button.style.padding = "0.5rem";
this.button.style.fontSize = "1.3rem";
this.button.style.borderRadius = "0.5rem";
this.button.style.color = "white";
this.button.style.background = "oklch(75% 0.183 55.934)";
this.button.style.cursor = "pointer";
this.button.addEventListener('click', () => {
this.count++;
this.button.textContent = `Count: ${this.count}`;
});
shadow.appendChild(this.button);
}
}
customElements.define('native-counter', NativeCounter);
The above would code would look like this if written in Lit (a lot neater in my opinion):
import { LitElement, html, css } from 'lit';
class LitCounter extends LitElement {
static properties = {
count: { type: Number },
};
constructor() {
super();
this.count = 0;
}
static styles = css`
button {
padding: 0.5rem;
font-size: 1.3rem;
border-radius: 0.5rem;
color: white;
background: oklch(75% 0.183 55.934);
cursor: pointer;
}
`;
increment() {
this.count++;
}
render() {
return html`
<button @click=${this.increment}>
Count: ${this.count}
</button>
`;
}
}
customElements.define('lit-counter', LitCounter);
Why Not Just Web Components
There is a case to be made for using bare web component without Lit. However, web components by themselves lack a lot of critical features we’ve come to expect from today’s front-end solutions.
A major one is reactivity. Without a tool like Lit or Stencil, you either implement your own reactivity, or forego it entirely, writing imperative code only, manually updating the DOM. This may be completely fine if your app hardly has interactivity. But as soon as you move into the CRUD realm, the tedium of imperative JS might become too much. And Lit has likely a far more robust implementation of reactivity than the one you plan to add yourself.
Same with most other features Lit provides out of the box. As your app grows in complexity, you’ll need to solve all these other problems Lit has already solved for you. If you’re sure your use cases are simple enough, maybe you don’t need Lit after all.
Server-Side Rendering
Lit is, of course, pure JavaScript. If you write your UI in Lit instead of regular HTML, your client will see absolutely nothing if they have JS disabled. Unless you opt for server-side rendering. Lit Labs has an SSR module you can use for this. Bear in mind, it’s marked as an experimental package and has given me some trouble with very niche use cases. But, for the most part, it’s perfectly useable.
Conclusion
Writing an entire project in Lit may or may not be for you, but Lit is undeniably one of the most useful tools in a web developer’s arsenal. You can jump into any project and sprinkle some Lit on top of what’s already there. It’s a good idea to be aware of what can be achieved with it, just in case!
