Eleventy + Lit

Announcing a new Lit Labs Eleventy plugin for static rendering of Lit components

The Lit team is pleased to announce an experimental preview release of @lit-labs/eleventy-plugin-lit, a new plugin for Eleventy that renders your Lit components as static HTML during your Eleventy build, and lets you hydrate them after your JavaScript loads.

Check it out now on GitHub and NPM, or read on to learn more about what it does, why you might want to use it, and how it works.

What does it do?

After you've added @lit-labs/eleventy-plugin-lit to your Eleventy config, then whenever you write a custom element tag in a markdown or HTML file, the initial state of that component's shadow DOM and styles will be rendered directly into the static HTML.

For example, given a markdown file hello.md:

And a component definition js/demo-greeter.js:

Then Eleventy will produce an HTML file hello/index.html like this:

This HTML allows the browser to paint the initial state of the component's DOM and styles, preserving all of the encapsulation boundaries of web components, even before a single line of JavaScript has downloaded!

Later, when the JavaScript definition of <demo-greeter> has finally loaded, the statically rendered component is upgraded to its fully interactive JavaScript implementation through a process called hydration.

Why should I use it?

Statically rendering components can be an effective method for reducing the time it takes between a page starting to load, and the content becoming visible. This is an important consideration that contributes to the responsiveness of your site, particularly for users with slower connections and devices.

By transmitting the initial state of your components as static HTML, the browser is able to paint the initial view much faster than it takes to download, parse, and evaluate the JavaScript implementations of those components.

For a deeper dive into the benefits of static rendering, check out Rendering on the Web, and for a discussion of how to measure this aspect of web performance, check out Largest Contentful Paint (LCP).

How does it work?

Lit Labs SSR

The plugin uses @lit-labs/ssr under the hood, which works by creating an instance of each component in a lightweight browser-like environment within the Eleventy Node process, and evaluating the element's template using a special version of Lit's render function. This special render function behaves much like the render function that Lit uses in the browser, except that it emits a stream of strings instead of writing to the DOM, allowing it to be efficiently written out as static HTML.

For more information about @lit-labs/ssr, check out its GitHub repo. We'll be expanding the documentation soon to help developers integrate @lit-labs/ssr into more tools and frameworks!

Declarative Shadow DOM

When @lit-labs/ssr renders a component, it uses <template shadowroot> HTML elements to represent the component's shadow DOM and styles. When the browser HTML parser encounters a <template shadowroot>, it applies that template's content as the shadow root of its parent element. This way, all of the DOM and style encapsulation guarantees of web components are preserved.

As of February 2022, Chrome and Edge have native support for Declarative Shadow DOM, but Firefox and Safari have not yet implemented it. A very small polyfill is available for browsers that don't yet have support. Integrating the polyfill into your site is documented in the @lit-labs/eleventy-plugin-lit README.

For more information about Declarative Shadow DOM, check out Declarative Shadow DOM.


While static rendering lets your components' initial paint happen as quickly as possible, the components won't yet be interactive, because their JavaScript implementations haven't loaded.

Hydration is the process where a statically rendered component is upgraded to its JavaScript implementation, becoming responsive and interactive.

Lit comes with automatic support for hydration via the special @lit-labs/ssr-client/lit-element-hydrate-support.js module. As long as this module has been loaded, Lit components will detect when they have been statically rendered, and will adopt their existing shadow root.

Hydration with Lit is very efficient, because Lit knows that it doesn't need to re-render the existing shadow root when it upgrades. If data changes after hydration, then only the parts of the shadow root that changed will be updated.

What's next?

Check out the roadmap for @lit-labs/eleventy-plugin-lit for some of the main features and fixes you can expect to land over the coming months.

If you try out @lit-labs/eleventy-plugin-lit, let us know if you have any suggestions or find any problems by starting a discussion or filing an issue.

Read more posts