A few of the unique things I try to emphasize when talking about Lit because it's so different from a framework:
Lit is just helpers to make web components. It's implementation detail. On the outside the components are just standard HTML elements.
Because of that, Lit makes no assumption that other elements you're using in your components are made with Lit. This low coupling preserves interop, and makes it easy to incrementally adopt Lit, and incrementally leave it if you wish. Low lock-in is an important principle for us.
Because of the low coupling, Lit doesn't have any centralized scheduling, diffing, etc. Each component is its own independent render root and schedules its own updates in microtasks. This has some great upsides - it's very easy to modify scheduling per component, and decouple costly subsections of a page to limit jank.
And we get great performance from the emergent global properties of independent roots. We check for data changes in the property setters for each component, so data updates only cause component updates along the paths in the tree that both use that data and see a change. Then lit-html, the template system, doesn't use VDOM, but remembers where data is bound to the DOM and only updates that if the data changed. It's very efficient.
Also, Lit requires no compiler to toolchain. You can use it from a CDN, or with import maps, or with a tool that resolves JS modules import specifiers. You can use decorators with TypeScript, or not. You can bundle or not. We do have TypeScript and ESLint plugins for working with templates.
Lit is awesome, thanks for maintaining it. I do more Svelte these days but have used Lit in the past and was very pleased with it.
Looking forward to using Lit in the future since I think it does a really great job of getting out of your way and being supremely easy to use and standards-adjacent.
> Because of the low coupling, Lit doesn't have any centralized scheduling, diffing, etc. Each component is its own independent render root and schedules its own updates in microtasks. This has some great upsides - it's very easy to modify scheduling per component, and decouple costly subsections of a page to limit jank.
Could you share some downsides?
> Also, Lit requires no compiler to toolchain. You can use it from a CDN, or with import maps, or with a tool that resolves JS modules import specifiers. You can use decorators with TypeScript, or not. You can bundle or not. We do have TypeScript and ESLint plugins for working with templates.
This is awesome -- thanks for
As for an actual new question, I'd love to know if there are any considerations on shared data in Lit -- with the just-web-components nature of Lit, data & reactivity are hard to fit in obviously but would be very beneficial to solve in a way that is just as easy to use as the rest of lit.
I took a stab at what it could look like and wrote a demo[0] and post[1], but have not kept up with the Lit community since then to see if there's some other solution/pattern gaining steam.
It sometimes makes working with _slotted_ children in a non-lock-in way difficult in terms of state synchronization as opposed to props.children in React. The solution here in an app would be to use a state manager, but it's much more difficult for components that do not want to require the user to use a state manager e.g. design systems.
Additionally, hydration and customElements.define() upgrade order is a different consideration compared to other mono-state frameworks when it comes to SSR.
In terms of state management:
There are plenty of tools out there like lit-mobx shopped by Adobe. The team has also made some examples that show how easy it is to integrate your own state manager into Lit using ReactiveController such as Redux. There is also work being done such as example implementations of Preact Signals integration:
Lit is great, one thing I learned from Web development in the last couple of decades is the less layers to debug between browser native support and UI application code, the better.
You have reactive properties to model the internal state of a component but what's the recommended way to manage global state? Example: I click a button in a row of a table and I make something happen outside the table, so several components upward the components tree of the page and then a few others downward in a different branch of the tree.
I'm sure there is a better way to do it but (10 seconds of thinking time) maybe a top component with just an empty div and a reactive property with the global state and the code to apply changes to the reactive properties of the appropriate children components, no matter how far down the tree? That seems something to standardize and not code from scratch every time.
There is a lit context package in lit-labs, which, like React context, can be used for passing the state across multiple layers of components; but I think that, just like with React context, it will not be sufficient if you have a lot of global state. In such a case, some state management library will probably be needed. I don't think Lit has any opinion on what such a library should be. I know some people like to leverage the web platform to its fullest, and just use a class that extends EventTarget for state management (see e.g. https://github.com/thepassle/app-tools/blob/master/state/ind...)
I'm just thinking aloud here based on your description (and note that I'm a backend/data engineer looking to build data apps with no front end experience), would this integrate well with htmx then since each component is independent?
I really like the htmx approach and have been looking for a good visualization component framework that will play nice with it.
Yes it would. Htmx works via attributes on html elements, Lit is just a layer over Web components, and Web components quite literally `extends HTMLElement` :)
Lit looks really cool it would be great to see some more examples and starter kits. Perhaps an example of how to build web components for use with other projects that are not Javascript based as well. Bundle up components into individual deployable files for example
Awesome work, thanks for maintaining it! What's the recommended strategy to do unit testing? I tried a couple of months ago to use jest but it gets messy really quick due to poor support for shadow DOM. Thank you!
It utilizes lit-html's compiled template support to transform HTML templates into lit-html templates and reuse the underlying efficient rendering / updating machinery.
I’ve been using lit in side projects (e.g. runno.dev) and really enjoyed it. Just like any framework it can be a bit confusing learning the primitives but I’ve found it as productive as React, Vue or Svelte.
The thing I like most about lit is that it embraces web standards. Sometimes that means the ergonomics are a bit strange. But it also means it gets performance benefits, and interoperability bonuses. Plus it feels like you’re learning something about the underlying platform while you’re using it.
The best example is that it uses reactive data binding via attributes for passing data down the tree, and native DOM events for passing data up the tree. That allows you all the same safety that a framework like React offers, but also means your component can be used by any other framework, or by vanilla JS (because they all support the DOM).
Lit looks really good, I keep trying to find an opportunity to try it out. I feel like web components and the tooling around them has finally got there. Major front end frameworks like React, Vue and Svelt finally also have good support for them.
What I really want is a good set of unstyled web components implementing many of the common UI controls that we all end up either building ourselves or finding an implementation of in our framework of choice. Things like drop down menus, select boxes, and tool bars. They could then be used with any of the common front end toolkits.
Creator of Shoelace [0] here. As someone who’s built multiple design systems and component libraries, I assure you that unstyled (or “headless”) components are often much more time consuming and painful to adopt than those with good default styles.
That said, I commonly find that most folks don’t want unstyled components because it’s quite a bit of work to style every single state of every single component. Most people just won’t do it or, if they try, they don’t do it right and they don’t do it completely.
What many folks do want are components that have simple, generic styles you can quickly tweak to match your site/app using a skill you already know: CSS. (This is something you can do with Shoelace’s 50+ web components already, but we’re working to make it even easier with additional CSS custom properties.)
Thanks so much for your work, the components look great and straightforward to use. Next time I'm building something will definitely try to give Shoelace a spin.
Can I ask, are ARIA attributes handled by default?
It is very true. Most of us who are not designers just want a very good looking default style. We can change if we want to later. It is a pain that react doesn't come with default style.
Agreed. I get excited to see "headless components" until I read the fine print that it's locked into framework x (usually React). I wish there was a robust headless AND framework-agnostic component library (preferably relying on Lit or Stencil).
Think thing is that Ionic have proven this can work with the massively underrated Ionic Framework (built with Stencil, which they also built). I just wish they expanded a little further into desktop UI components and provided an no/low styled variant - I dislike Material as a base style, it's too opinionated.
They are 50% of the way to building a universal mobile+ desktop ui toolkit.
Do the same with Ionic Capacitor, make a desktop version, and that would be an incredible improvement over Electron - it uses the OS supplied web view.
I haven't used Lit yet, but have used lit-html standalone professionally for some projects. (lit-html is a very small, very performant library and the templating solution for Lit).
I'm very happy with it. I don't have a use-case for web components (so far) and am happy to just wire up dom events to state changes to lit-html. It requires _very_ minimal plumbing and is very easy to reason about.
Been using Lit for a few years now, it just keeps getting better. It does what it does, and stays out the way. Please don't call it a framework though, the best part of Lit is that is basically some (very lovely!) sugar over standards built into your browser. And as browsers keep improving (at an amazing pace IMO) Lit keeps getting smaller, which might be my favorite thing about it.
One of my complaints with Lit and others[0] is they're most definitely becoming something of an "Angular Lite". Heavy on decorators if you want developer ergonomics, but yet they embrace none of the advanced toolchain things you get with angular-cli. Due to this, it can feel very clunky to build apps using web component frameworks like this. The community as a whole seems very anti-tooling and I think its to the long term detriment of the ecosystem.
The only exception is Stencil[1] that I can find.
They're also missing first class concerns you get handled with other frameworks, like SSR, compiled templates etc. There's no web component equivalent to Next.js that I am aware of.
I don't like using them for design systems. You bail on your framework of choice rendering model, and that's problematic to me.
Lit doesn't require decorators, and if you do use them they only require a pretty standard TypeScript or Babel compile.
Are decorators the only thing making Lit like Angular? Angular is not the only project that uses decorators, and decorators are standardized in JS now.
Stencil is good, but requires a compiler where Lit doesn't.
What tooling are you looking for? We have template type checkers and eslint plugins. Starter kits. Prettier works for formatting...
I am aware you don't need decorators, this isn't what I was saying. I said its the only way to use Lit with any measure of good developer experience.
Decorators are not the only thing that make it like Angular. The way templates work, template helpers (directives), controllers are all very Angular like in practice.
Tooling is much more than linters, eslint plugins and starter kits.
Unit & e2e testing helpers, build tools, HMR / dev server support. These all matter too and its important that they keep up to date with expectations of developers in what they expect out of these experiences. Even better when it is all rolled up in a nice CLI interface.
Not to mention it would be nice to have optimized convenience features, like Vue style SFCs for authoring components and templates.
Stencil requiring a compiler is not a negative. It makes it an end to end solution and thats very popular for a reason (Next.js, Nuxt, Sveltekit are all very popular for a reason).
I believe strongly that projects need to provide these things as 1 party concerns. I think the Vue community is proof positive of how strong this can be for the ecosystem.
I'm certain between Google, Microsoft, Ionic, and many others there could be real solutions for all this. After all, the biggest advantage of using web components is they are a shared interface
Sounds like my kind of community as I'm also extremely anti-tooling.
I want to feel like I'm working with native browser features as much as possible.
Personally, I would even consider doing a project with plain HTMLElement. If I found that I absolutely needed the convenience of state reactivity, only then I would use Lit.
I took an interest in Lit at one point and I gave up when I discovered that its core functionality is ungoogleable.
At the heart of Lit are components named "html" and "css".
Confusion reigns, search engines cower, beginners try to grasp the conceptual different between html and actual html and css and actual css. You'd think the authors would have gone to the trouble of naming those critical components something like lithtml and litcss to give them a little searchability and to deconfuse them, but it seems not.
It's not, and hasn't been for a long time. It's its own DSL with unexpected constraints on what you can use with it.
`<some-component
attribute="string only"
?boolean=${boolean}
.property=${any_js_variable}
@event_name=${callback_function}>
none of this is "just html"
</some-component>
`
It's not too bad. At least, not nearly as bad as naming your language after the most common English verb of motion, especially when your company is literally Google itself.
I love Lit! Easy, fast, super lightweight as it's a thin layer over standards-based web components. Using it for all my side projects, as well as stuff at work.
Server-side rendering is still a missing piece. But overall, I'm very happy using it going forward.
And if you need a web component library to pair it with, Shoelace[0] is a fantastic library of prebuilt web components using Lit. I'm loving this stack.
I think web components were almost a good "built-in" way of doing React/Vue. Where it lost me was the Shadow DOM. I get that it's supposed to encapsulate the contents of a component and restrict JS/CSS to itself, but it's overkill IMO. It's basically like having a bunch of iframes and makes it much harder to query things, which is very much unlike the rest of the DOM. I don't need guard rails to tell me how to do encapsulation.
Encapsulation might be overkill for a single developer, but it very much matters for teams and using third-party components.
If you want to drop in a calendar component into your page from npm, it helps if that component's styles don't leak into the page, and if page scripts don't accidentally mess with component internals.
This seems overstated. It’s different but not really harder.
document.querySelector('my-lit-element').elementIWant;
class MyLitElement extends Lit {
get elementIWant() {
return this.renderRoot.querySelector(...);
}
}
Though, maybe one doesn’t like querying twice. I’m not sure of performance implications there, to be honest, but I’d expect it to be negligible in most cases.
I think framing it this way can lead to real gripes with the interface. Web Components are a great way to build individual components that can be reused across an app, website, or shared as part of a library. They are like helper functions for HTML.
They don't work as well for building apps, sure you can do it, but tools like React/Vue/Svelte are much better at building a whole app experience. Particularly when you consider meta-frameworks and the ecosystem around them.
I remember when the language was Web Components would replace frameworks, this was something the people pushing the standards were actively championing at the time and was really one of the main goals of Polymer as well.
They could work well for building apps if the ecosystem was more invested in giving developers what they actually want in a timely manner. (Looking at you template instantiation)
The problem with using them for component libraries is that you break your rendering paradigm of the framework you're using, and that can lead to situations like trying to add event handlers to child components impossible for instance, or having to over-use refs
It's worth noting that many of these pain points are directly related to Shadow DOM's encapsulation. While there are many benefits to some types of widely shared components to strong encapsulation, the friction of strong encapsulation has prevented most developers from adopting Shadow DOM, to the point of there being alternate proposals for style scoping that don't use Shadow DOM. We urge browser vendors to recognize these barriers and work to make Shadow DOM more usable by more developers.
A few of the unique things I try to emphasize when talking about Lit because it's so different from a framework:
Lit is just helpers to make web components. It's implementation detail. On the outside the components are just standard HTML elements.
Because of that, Lit makes no assumption that other elements you're using in your components are made with Lit. This low coupling preserves interop, and makes it easy to incrementally adopt Lit, and incrementally leave it if you wish. Low lock-in is an important principle for us.
Because of the low coupling, Lit doesn't have any centralized scheduling, diffing, etc. Each component is its own independent render root and schedules its own updates in microtasks. This has some great upsides - it's very easy to modify scheduling per component, and decouple costly subsections of a page to limit jank.
And we get great performance from the emergent global properties of independent roots. We check for data changes in the property setters for each component, so data updates only cause component updates along the paths in the tree that both use that data and see a change. Then lit-html, the template system, doesn't use VDOM, but remembers where data is bound to the DOM and only updates that if the data changed. It's very efficient.
Also, Lit requires no compiler to toolchain. You can use it from a CDN, or with import maps, or with a tool that resolves JS modules import specifiers. You can use decorators with TypeScript, or not. You can bundle or not. We do have TypeScript and ESLint plugins for working with templates.
Looking forward to using Lit in the future since I think it does a really great job of getting out of your way and being supremely easy to use and standards-adjacent.
> Because of the low coupling, Lit doesn't have any centralized scheduling, diffing, etc. Each component is its own independent render root and schedules its own updates in microtasks. This has some great upsides - it's very easy to modify scheduling per component, and decouple costly subsections of a page to limit jank.
Could you share some downsides?
> Also, Lit requires no compiler to toolchain. You can use it from a CDN, or with import maps, or with a tool that resolves JS modules import specifiers. You can use decorators with TypeScript, or not. You can bundle or not. We do have TypeScript and ESLint plugins for working with templates.
This is awesome -- thanks for
As for an actual new question, I'd love to know if there are any considerations on shared data in Lit -- with the just-web-components nature of Lit, data & reactivity are hard to fit in obviously but would be very beneficial to solve in a way that is just as easy to use as the rest of lit.
I took a stab at what it could look like and wrote a demo[0] and post[1], but have not kept up with the Lit community since then to see if there's some other solution/pattern gaining steam.
[0]: https://mrman.gitlab.io/services-as-dom-elements
[1]: https://vadosware.io/post/sade-pattern-services-as-dom-eleme...
https://github.com/alexanderweiss/mobx-lit-element
and (documented as based on the former)
https://github.com/adobe/lit-mobx
already out there, and next time I get some Copious Free Time I plan to experiment with adobe's connector plus mobx-state-tree (https://mobx-state-tree.js.org/intro/welcome).
NB: I haven't used the above for anything 'real' yet ... but I do think at the very least it's worth a look to steal ideas from.
It sometimes makes working with _slotted_ children in a non-lock-in way difficult in terms of state synchronization as opposed to props.children in React. The solution here in an app would be to use a state manager, but it's much more difficult for components that do not want to require the user to use a state manager e.g. design systems.
Additionally, hydration and customElements.define() upgrade order is a different consideration compared to other mono-state frameworks when it comes to SSR.
In terms of state management:
There are plenty of tools out there like lit-mobx shopped by Adobe. The team has also made some examples that show how easy it is to integrate your own state manager into Lit using ReactiveController such as Redux. There is also work being done such as example implementations of Preact Signals integration:
https://github.com/lit/rfcs/blob/preact-signals/rfcs/NNNN-pr...
I'm sure there is a better way to do it but (10 seconds of thinking time) maybe a top component with just an empty div and a reactive property with the global state and the code to apply changes to the reactive properties of the appropriate children components, no matter how far down the tree? That seems something to standardize and not code from scratch every time.
I'm just thinking aloud here based on your description (and note that I'm a backend/data engineer looking to build data apps with no front end experience), would this integrate well with htmx then since each component is independent?
I really like the htmx approach and have been looking for a good visualization component framework that will play nice with it.
Is it maybe no longer associated?
0 - https://lit.dev/articles/lit-for-polymer-users/
[0] https://modern-web.dev/docs/test-runner/overview/
It utilizes lit-html's compiled template support to transform HTML templates into lit-html templates and reuse the underlying efficient rendering / updating machinery.
The thing I like most about lit is that it embraces web standards. Sometimes that means the ergonomics are a bit strange. But it also means it gets performance benefits, and interoperability bonuses. Plus it feels like you’re learning something about the underlying platform while you’re using it.
The best example is that it uses reactive data binding via attributes for passing data down the tree, and native DOM events for passing data up the tree. That allows you all the same safety that a framework like React offers, but also means your component can be used by any other framework, or by vanilla JS (because they all support the DOM).
What I really want is a good set of unstyled web components implementing many of the common UI controls that we all end up either building ourselves or finding an implementation of in our framework of choice. Things like drop down menus, select boxes, and tool bars. They could then be used with any of the common front end toolkits.
That said, I commonly find that most folks don’t want unstyled components because it’s quite a bit of work to style every single state of every single component. Most people just won’t do it or, if they try, they don’t do it right and they don’t do it completely.
What many folks do want are components that have simple, generic styles you can quickly tweak to match your site/app using a skill you already know: CSS. (This is something you can do with Shoelace’s 50+ web components already, but we’re working to make it even easier with additional CSS custom properties.)
[0] https://shoelace.style/
Thank you very much.
Can I ask, are ARIA attributes handled by default?
It's a webcomponent that gracefully degrades to es5 + polyfills for IE (this was years ago).
Getting the rollup build to work correctly was a bitch and a half, but it turned out nice and it's still in use today.
They are 50% of the way to building a universal mobile+ desktop ui toolkit.
Do the same with Ionic Capacitor, make a desktop version, and that would be an incredible improvement over Electron - it uses the OS supplied web view.
The whole shadcn/tailwind philosophy of having you own your components is the future.
I'm very happy with it. I don't have a use-case for web components (so far) and am happy to just wire up dom events to state changes to lit-html. It requires _very_ minimal plumbing and is very easy to reason about.
One of my complaints with Lit and others[0] is they're most definitely becoming something of an "Angular Lite". Heavy on decorators if you want developer ergonomics, but yet they embrace none of the advanced toolchain things you get with angular-cli. Due to this, it can feel very clunky to build apps using web component frameworks like this. The community as a whole seems very anti-tooling and I think its to the long term detriment of the ecosystem.
The only exception is Stencil[1] that I can find.
They're also missing first class concerns you get handled with other frameworks, like SSR, compiled templates etc. There's no web component equivalent to Next.js that I am aware of.
I don't like using them for design systems. You bail on your framework of choice rendering model, and that's problematic to me.
[0]: https://www.fast.design/
[1]: https://stenciljs.com/
Are decorators the only thing making Lit like Angular? Angular is not the only project that uses decorators, and decorators are standardized in JS now.
Stencil is good, but requires a compiler where Lit doesn't.
What tooling are you looking for? We have template type checkers and eslint plugins. Starter kits. Prettier works for formatting...
https://lit.dev/docs/tools/development/
Decorators are not the only thing that make it like Angular. The way templates work, template helpers (directives), controllers are all very Angular like in practice.
Tooling is much more than linters, eslint plugins and starter kits.
Unit & e2e testing helpers, build tools, HMR / dev server support. These all matter too and its important that they keep up to date with expectations of developers in what they expect out of these experiences. Even better when it is all rolled up in a nice CLI interface.
Not to mention it would be nice to have optimized convenience features, like Vue style SFCs for authoring components and templates.
Stencil requiring a compiler is not a negative. It makes it an end to end solution and thats very popular for a reason (Next.js, Nuxt, Sveltekit are all very popular for a reason).
I believe strongly that projects need to provide these things as 1 party concerns. I think the Vue community is proof positive of how strong this can be for the ecosystem.
I'm certain between Google, Microsoft, Ionic, and many others there could be real solutions for all this. After all, the biggest advantage of using web components is they are a shared interface
I want to feel like I'm working with native browser features as much as possible. Personally, I would even consider doing a project with plain HTMLElement. If I found that I absolutely needed the convenience of state reactivity, only then I would use Lit.
At the heart of Lit are components named "html" and "css".
Confusion reigns, search engines cower, beginners try to grasp the conceptual different between html and actual html and css and actual css. You'd think the authors would have gone to the trouble of naming those critical components something like lithtml and litcss to give them a little searchability and to deconfuse them, but it seems not.
https://lit.dev/docs/components/overview/
I agree that those are odd choices and the arguments provided seem reasonable I.e. they’re likely ungoogleable, and beginners would be confused.
It's not, and hasn't been for a long time. It's its own DSL with unexpected constraints on what you can use with it.
Deleted Comment
Deleted Comment
Server-side rendering is still a missing piece. But overall, I'm very happy using it going forward.
And if you need a web component library to pair it with, Shoelace[0] is a fantastic library of prebuilt web components using Lit. I'm loving this stack.
[0]: https://shoelace.style
If you want to drop in a calendar component into your page from npm, it helps if that component's styles don't leak into the page, and if page scripts don't accidentally mess with component internals.
This seems overstated. It’s different but not really harder.
Though, maybe one doesn’t like querying twice. I’m not sure of performance implications there, to be honest, but I’d expect it to be negligible in most cases.They don't work as well for building apps, sure you can do it, but tools like React/Vue/Svelte are much better at building a whole app experience. Particularly when you consider meta-frameworks and the ecosystem around them.
They could work well for building apps if the ecosystem was more invested in giving developers what they actually want in a timely manner. (Looking at you template instantiation)
The problem with using them for component libraries is that you break your rendering paradigm of the framework you're using, and that can lead to situations like trying to add event handlers to child components impossible for instance, or having to over-use refs
Doesn't mean it's a good feature. This is recognised even by people who push them: https://w3c.github.io/webcomponents-cg/2022.html
--- start quote ---
It's worth noting that many of these pain points are directly related to Shadow DOM's encapsulation. While there are many benefits to some types of widely shared components to strong encapsulation, the friction of strong encapsulation has prevented most developers from adopting Shadow DOM, to the point of there being alternate proposals for style scoping that don't use Shadow DOM. We urge browser vendors to recognize these barriers and work to make Shadow DOM more usable by more developers.
--- end quote ---