Experimenting with lit-html

December 21, 2018

The Polymer team at Google work on a higher abstraction over web components. I use that library from the 0.10.0 version and today I migrated an app to the 1.0.0-rc.1.

This view library is incredibly light (3kb), intuitive and fast. A lot of people started to use it after the Polymer Summit presentation talk.

Rendering view with lit-html

We use functional programming to create and compose our views. We can formulate our rendering logic with the following : UI = fn(data).

Lit concepts are pretty common for a frontend developer: life-cycle, directive, binding… There is a lot in common with React, but without the JSX and the virtual-DOM buzz-word.

To render a template with Lit we use a native functionality of JavaScript (ES6) : the literal template which let us interpolate dynamic values :

const sayHello = (name) => html`hello ${name}`;
render(sayHello('Giles Jown'), document.body);
// => hello Giles Jown

Using the render function Lit build and update the DOM when an expression changed. Immutability is required when changing the state, otherwise the re-rendering does not operate.

Lit also comes with its directive concept, which is function that will be executed during the rendering process. This way we can factorize many rendering behaviors.

const getUserProfile = (userId) =>
    (resp) => resp.json(),
    (err) => console.error(err)

    getUserProfile().then((user) => html`Hello ${}`),
    html`Loading data...`

There are several built-in directives, for example until which display a fallback content while the given Promise isn’t resolved yet. Lit is also highly extensible, we can built our own directives.

Building a web component

Now let’s see how to use the lit-html rendering logic in a higher building block. With lit-element we can embed the template, the style and the JavaScript in a web component. It’s just a tiny wrapper around the native web components.

import { css, html, LitElement, property } from 'lit-element';
import { nothing } from 'lit-html';

export default class PageComponent extends LitElement {
  @property({ type: Boolean })
  showNavbar = true;

  static get styles() {
    return css`
      .page-wrapper {
        max-width: 780px;
        margin: 0 auto;

  render() {
    return html`
      ${this.showNavbar ? html`<ez-navbar></ez-navbar>` : nothing}
      <main class="page-wrapper"><slot></slot></main>

customElements.define('ez-page', PageComponent);

Lit-element works well with TypeScript, just as Angular it relies on annotations to declare component properties. Now I can display our components using the render function :

    <ez-page .show-navbar="${false}">

Or directly in the HTML document :

  <script src="bundle.js"></script>

Like every SPA components will be rendered only when the bundle.js file will be parsed and executed by the browser.

What differences with the rest of the market?

Lit offers a nice alternative to the classic Angular, Vue and React with some different ideas. Lit Element relies on native web components, which is the only one to do this today. Web components come with a bunch of pros and cons, it’s up to you to decide when it’s appropriate or not.

Lit is fresh, it uses modern JavaScript to run extremely fast in the browser while keeping our bundle light.

However I do not recommend using lit for any use cases. You will need to compose with a bunch of others libraries (HTTP client, routing…) to build a real-world SPA, which leads in high maintenance costs.

Also we take the risk to build our app in a non-conventional way since we can stick with every library.

For me the biggest downside is the Server Side Rendering incompatibility which exclude using lit for any SEO oriented apps.

If you want to go further there is a list of well crafted applications with Lit.

I'm Edouard Bozon, I play almost everyday with web technologies. I focus my work on JavaScript, mainly around Angular and Node.js. I'm self employed, always open to new opportunities, so let's keep in touch.