Get started with Web Components – enabling you to define new HTML elements that work everywhere regular HTML does. This talk will focus on Lit, a suite from Google that helps you create WCs with features you'd expect like data-binding and declarative definitions. It'll also cover how we've used them to build one of the web's jolliest sites, Google's Santa Tracker 🎅
Web Components, Lit and Santa 🎅
AI Generated Video Summary
Web Components and the Lit library are introduced, highlighting their ability to create custom elements and replicate built-in components with different functionality. The use of semantic HTML and the benefits of web components in development are emphasized. The features of Lit, such as data binding and rendering, are discussed. The Santa Tracker is showcased as an example of web components being used in educational games. The compatibility of web components with other frameworks and their versatility in creating small widgets or large applications are highlighted.
1. Introduction to Web Components and Lit Library
Hey there, my name's Sam, and I'm here today to talk about Web Components, the Lit library, and Santa Tracker. Firstly, we're here to talk about web components. So let's have a bit of background on elements, and what pages are. Web components, fundamentally, let's us write our own elements. These are first-class citizens that work just like regular HTML elements. The goals of this talk are to introduce you to web components and their component parts, and to learn about Lit, a very opinionated web component library that Google ships.
Hey there, my name's Sam, and I'm here today to talk about Web Components, the Lit library, and Santa Tracker. But first, some background on me. I'm lucky enough to be the lead on Santa Tracker. It's something I've done for five or six years now. Luckily, I don't have to do it all year round, only for a few months around the holiday season. Otherwise, I would go insane, just to be clear. I also work on content sites like web.dev and developer.chrome.com.
For me, personally, what do I like? I like pushing the boundaries, doing weird web things. You can read my blog if you are curious about more. And I have some dislikes here too. I like building websites in a very sudden way, and I think big builds, during development, really slow you down. I'd love to see a much faster development process, and I think a lot of tools now are do help support that.
Firstly, we're here to talk about web components. So let's have a bit of background on elements, and what pages are. Now, we all know HTML pages are made up of a bunch of different elements. These can be semantic elements that mostly just affect your style and also are important for things like screen readers, and also a bit of semantics for you as a developer, things like header and section. But they can also be elements that have functionality, things like A and button, and elements like dialogue and details, and more advanced versions of those that have a state that changes. Web components, fundamentally, when it gets down to it, let's us write our own elements. These are first-class citizens that work just like regular HTML elements. I'm going to talk through an example of my details, which I'll get to shortly.
So what are the goals of this talk? I want you to be introduced to web components and their component parts. This is a fairly high-level talk. I want to make that clear. We'll be skipping over some more nuanced things, which, hopefully, I will point you in the right direction so you can go find out more. I want you to learn about Lit, a very opinionated web component library that Google ships, which is really the best place to get started writing web components. And also, I'd be very happy in another tab if you open Santa Tracker and click around and play some games and just try to work out which games and what parts of the site are run with web components. So let's talk through details. Details is a really interesting element I mentioned before. It's got a bunch of functionality. If you haven't seen it before in action, what it does it shows the summary text, which is the thing on the top here, and only shows the longer form description when you click on that summary.
2. Creating Custom Details Web Component
I want to write my details as a web component that opens upwards. It's a powerful example of how web components can reproduce a built-in component but with different functionality. By defining the inner HTML of the shadow root and adding behavior, we can create this element with zero library cost. It's interoperable with evergreen browsers and fundamentally indistinguishable from the regular detailed element. Web components have access to the element lifecycle, allowing us to know when an element is being created, added, or removed from the page.
Makes a lot of sense, and it's really handy. I want to write my details. Now, this will be very similar to the regular details element, but with one key difference. This is what it will look like as a web component. It can't look exactly the same. We have to use this slot thing here, but I'll mention how that works later on.
So my fundamental difference of my details versus details is that these details should open upwards. Now, this may not be the most important thing on the web, but I thought it was a pretty fairly cute example to show just how powerful web components are, that I can reproduce a built-in component, a cute little widget, but do something completely different. So I want to talk through how this works. Fundamentally, we create this class here, and then follow on by defining its inner HTML of something called the shadow root, which I'll get to a little bit later. But I create some code here. I then grab some references to some elements within that shadow root and add some behavior.
Now this behavior is pretty standard stuff. When I click on this element here, I want the other stuff to toggle state. And so I'm going to open and close this element by making it hidden or not hidden, and I'm also going to change the emoji representation of whether the element is open. So we've built this great little element, and the best part of it for me is that it has zero library cost. Obviously, the element has a bit of code and that needs to run, but it costs you nothing else. There's no library to attach or download or include. And every evergreen browser, about 95% of all browsers today, supports this out of the box. This is something you can just use. The next best part is this is just a standard way of interoperability. Turns out my details, if we do a little bit more work to make it a bit more polished, will be fundamentally indistinguishable from the regular detailed element. Nothing you use should really care that it's my details versus details. Of course, it has different functionality, but you know, it looks, smells, tastes, quacks, whatever metaphor you like. Exactly the same as anything else. So, these elements are just like HTML. And the reason they're just like HTML is because we have access to these two basic components of Web components. Firstly, we have access to the element lifecycle. We know when an element is being created, that's in the constructor. We know when it's being added to the page and removed from the page.
3. Custom Elements and Shadow DOM
To be a custom element, you must be named with a dash. Emoji are valid strings. The second part of Web components is shadow DOM. HTML can be a good way to build things for the web. You can hold web components any way you like. Examples include the Santa app.
The other thing too is that to be a custom element, you must be named with a dash in it. And that's a very simple rule. There's no built-in elements that have a dash, so your elements must have a dash.
The most fun part of this, of course, is that emoji are valid strings. So it turns out your element can be called fire-dash-fire-truck emoji if you like.
The second part of Web components is the part that lets you encapsulate custom HTML and styles. I've used this in the example before to create a structure that our other elements fit within. This is called shadow DOM. Shadow DOM fits within the shadow root. These terms are interchangeable. They mean slightly different things. But if you ever hear someone talk about shadow DOM or shadow root, they're talking about the same thing.
One thing I want to talk about before we go any further is kind of this philosophical question of the web. One question we ask ourselves is do you think HTML is a very good way to build things for the web? That sounds counterintuitive. We've got HTML and that's how you build websites. But many frameworks choose to use HTML as a render target. They output to divs or other elements that maybe don't have a lot of semantic meaning but they're based on some more complicated concepts that you're building in some other framework library or some component library somewhere else. And that's totally valid. But there's an argument to make that the web can be semantic. I'll get to that later.
One other concern is that you can hold web components any way you like. And what I mean by that is, well, I'm not here coming from the position of a framework author or a library saying this is the way we think you should build things. We have guidance. We've got suggestions of how you should use the web component lifecycle to productively build elements. But in the end, you know, I'm a talk, not a cop. You can build things the way you want and you can hold it badly or really well or in that way that works for your application and not someone else's. And that's totally fine. Some interesting examples of this are we previously had an element called Santa app. Now that kind of does what it says in the tin. It was our whole Santa Tracker application.
4. Web Components and Semantic HTML
So if you load up the website, you would literally see one element called Santa app. We found that web components work best when they're kind of compartmentalized things that represent a single unit of work. We often use HTML because it's semantic. Using divs like this isn't ideal. For a Gmail equivalent site, I would use headers, navs, and custom elements that provide semantic meaning. Web components are here now, and they have made developing for the site quite a delight. GitHub uses a web component to turn absolute dates into relative dates.
Secondly, one thing I want to call out, we often use HTML because it's semantic. We use header and section because that has meaning to us as developers and to people looking at our pages using screen readers. Now I can create an element called fancy link, but maybe I shouldn't because turns out, browsers don't understand that, right? They understand A to mean link. Now, you can work around this. You can construct your element with A elements, but it's worth considering and keeping in mind, but before you just dive in and want to replace everything that HTML gives you for free.
So I'd like to use a concrete example of divs versus semantic elements. Now, using divs like this isn't really ideal. Although I suspect Gmail is targeting these divs, rather than building them by hand. The class names there are pretty gross. They do actually have some semantic meaning here. So here is a role equals main hidden within this big, massive layout. But to me, if I was writing a Gmail equivalent site, I think maybe I would use things like headers, navs, some built-in elements, along with a bunch of custom elements, that really provide some semantic meaning. You know, we've got this search icon here. We've got this compose button, and then individual messages. And to me, like as a developer, this seems like a much nicer way to build the site. This is obviously up to you, but this is one of the ways you can use web components. And you might imagine building a site like this. Fundamentally, though, web components are here now, right? You see them all over the place, you probably have used them without even realizing. For Santa Tracker, our big use case here is to drive the shell and the kind of layout of the site. We've actually got a lot of old code, and those games live within iframes, and often, you know, 10-plus-year-old code that's built with jQuery, and they're a whole mess. It's one of the powers of the web, right? Like, I don't have to change that code dramatically, but we do have to support it. But all the new stuff is all web components, which has made the developing for the site really quite a delight. We also see some really interesting use cases out there on the web. GitHub somewhat semi-famously shipped dates down to the client as, like, 2021-05-5. What they then do at runtime is they have a web component which turns that absolute date into a relative date. This is actually really cool because you can actually cache that page almost forever, and then at runtime, the web component is going to replace that absolute time with a relative time.
5. Web Components and Custom Elements
On a personal note, I use web components to wrap up interesting demos in a single element. The power of custom elements lies in their ability to connect elements regardless of how they are added to the page. Custom elements extend HTML elements and have connected and disconnected callbacks. It's important to clean up after yourself and stop any ongoing processes when an element is disconnected from the page. There are nuances in adding elements to the page before the code arrives.
So I mentioned the two parts of web components that I'm going to cover. One of them is custom elements, which is really about code loading when it sees a certain element, and shadow DOM, which is about interesting layouts for your elements. What I'm going to do is talk through this button, the elf maker button, which is really a button that loads a particular game on Santa Tracker. So this is actually a really hard problem, right. If I have this button, and I call it game start, I actually don't know when it gets added to the page. In this case, I'm sitting in HTML. I could probably call an upgrade method or use a mutation observer with a bunch of flags. But by the time I do all that, it's kind of awkward, and I've kind of written a polyfill for the feature I'm about to mention. So if I give this a dash, and as I mentioned before, anything with a dash in it can be a web component, the browser will say, cool, I've got a Santa card, I know that it's run this class over here. It doesn't matter how it gets added, whether it's through HTML, another framework, being on your page that you ship to your clients, those two things will be connected up. That's really the power of custom elements. What this looks like in terms of classes is, you know, a fairly boring class. This extends HTML element and has two major callbacks. It's got a connected callback and disconnected callback. If you've written any other code with other frameworks, this metaphor is not new. Or unmount or connected or these kind of verbs that you've heard a lot.
Lastly, what I have to do is this element doesn't for free show up on my page. I have to call this global custom elements.define that really ties the name to the class itself. So, why are these methods important at all? Turns out it's about being a good web citizen and cleaning up after yourself. In this case, I'm using an animation library to play my animation as part of this card. If we don't stop playing when I'm disconnected, maybe I'm going to leak timeouts or animation frames as the animation tries to keep working. This is the last time you get told about an element being disappeared from the page, so it's the right time to clean up after yourself. I want to talk about some more nuances of the life cycle. You can actually add Santa card to your page before the code arrives, that's totally fine, you can do this in either order. There's some tricky nuances about styling it before the code arrives.
6. Lifecycle, Shadow DOM, and Slot Element
At that point, it's just a blank element, doesn't do anything, so there's some options there. One thing I want to push is that the life cycle that we talked about, connected to disconnected, we think is really important. Now O components are a standard, you can use them how you like, like I mentioned, but we really think that doing set up work and tear down work on connected and disconnected makes a lot of sense. Once an element's on the page, it starts being active and should start doing things in a way that the user would expect.
Finally, I also want to call out two methods, attribute change callback and the static getter for observed attributes. Now, these together give you callbacks when certain attributes change, which you can do like mutation observer, but it ties up a lot more nicely here as part of this whole, API. Next I want to talk about shadow DOM, which can make your elements pop. This card here isn't just a standard card with text in it, although the lovely thing about working with it on your page is that you kind of just treat it like that. It does have a shadow root, which I'll get to in a second, and I'll call that shadow DOM and the shadow root is most commonly seen on components. It's not the only place it can work, but it's 99% of the time the only thing you'll see here. Now once we talk with the shadow root open, which is something you can do using dev tools or whatever, you can actually see that we've created it using a bunch of other elements. So in this case, the Santa card is made up of a real button as well as a SVG that has this pretty animation in it. What's really exciting here is that I create a style tag, and in the style tag I style every button to be blue. But importantly, it's only every button that's within the shadow root. This doesn't leak out, right? Every button on my page doesn't suddenly become blue. That would be really awkward.
7. Understanding Lit and Shadow DOM
Lit works a certain way, frameworks work a certain way, and so they'll take their interpretation and layer their polyfills on top of that. Slots can also be named and have default content if there's nothing in them. The CSS rules about the shadow DOM and shadow scoping take a bit of getting used to. While they are scoped and nothing breaks into them, they don't leak data in from the outside, things like fonts do, and this makes sense from an accessibility point of view.
Lit works a certain way, frameworks work a certain way, and so they'll take their interpretation and layer their polyfills on top of that. Which doesn't really speak to the ethos of web components for me. Slots can also be named and have default content if there's nothing in them. That sort of makes sense. And the CSS rules about the shadow DOM and shadow scoping take a bit of getting used to. While they are scoped and nothing breaks into them, they don't leak data in from the outside, things like fonts do, and this makes sense from an accessibility point of view. If a user set a large font as part of a style sheet, your elements might end up looking really big, or in different ways you don't expect. And this is something that I think people potentially don't expect when they're first writing shadow DOM.
8. Shadow DOM, Lit-element, and Data Binding
There are additional features tied to shadow DOM, such as CSS variables, Part, and Slotted. Lit-element, formerly known as Lit-element, is Google's opinionated way to write Web Components. It has a small footprint and is focused on data binding. Lit uses decorators to simplify the creation of custom elements. Styles are returned as an object, providing performance benefits and reuse. Properties handle data binding, and the render function uses tag template literals for fast rendering. The template syntax allows for the use of special attributes, such as Boolean properties.
There's also a few features that are tied to shadow DOM but not strictly related. There's a CSS variable spec, which lets you specify another kind of API that can change your shadow elements, as well as things like Part and Slotted, which let you change both the targeted parts within your shadow DOM, as well as the directly slotted elements under your shadow root. And so we use Slotted for example, to change the text to the lobster font in the example before. It's a sort of mini-API to specify, well, what are the direct descendants of my child that I'm rearranging end up looking like?
So now I want to talk about lit-element, which is Google's opinionated way to write Web Components. It's called Lit now, it was formerly called Lit-element, and it's a descendent of something called Polymer, which you might have heard of, and Google used to run conferences on, you can look that up. It's fairly small, it's got a 5-kilobyte GZIP footprint, and you can find out more at lit.dev. So the main reason you use Lit over regular Web Components is data binding. We have this name attribute here, and it's going to render as hello-name, or in this case, hello-world. Now, Lit is obviously very powerful. It's much more than just data binding, but it's the main difference you'll see when you first get started.
9. Properties, Events, Rendering, and Directives
So properties versus attributes, remember that attributes can only be strings, while properties can handle more complex objects. Events in Lit can be handled through methods or inline handlers. Lit allows rendering arrays of HTML elements, making it easy to create lists. Directives in Lit, like Repeat and Until, provide powerful ways to enhance functionality. Additionally, reactive controllers offer an alternative way to tie into the web component lifecycle.
So it lets you toggle things like disabled attributes. If you specify a dot, this means a property. Now properties versus attributes, there's a whole other thing, but fundamentally, remember that if you're trying to pass through complicated objects, attributes don't make sense. Attributes can only be strings. So if you have an array or an object and you want to pass it to an element, you have to go dot property equals that property value.
Next, we have events. Now events are kind of interesting to me because I can just say, at click, for the click event, call this method. But it turns out I can just write an inline handler as well. This isn't special, right? Lit isn't interpreting the code and saying that's the property to call. It can just call code that you pass inline. And that's kind of cool to me.
Now, I want to give a slightly longer example. This is rendering a list of emoji. So what I can do here is I can actually render an array of other HTML elements. So in this case, I'm rendering a list of these three emoji here. And that just works. I return an array and it will just make it happen. Secondly, I want to show examples of how these properties and events work. So the property here on the left is passing to another web component called add widget. And that's saying don't show these elements. You know, it already got these emoji. And finally, when a user, you know, hits enter, I'll get a call back on the on add method.
Some other parts of lit that I want to call out are it's got these powerful things called directives. Repeat lets you do better lists that don't cause it to re-render every time. Until is also a good directive that lets you do things like show spinners until a promise is resolved. Which makes sense for a lot of, you know, things that talk to the internet or some database. And directives are a way to really write powerful overrides to lit's default behavior. There's this new feature called reactive controllers. Which is sort of similar, but a bit different. We've talked a lot about the web component life cycle, but actually, reactive controllers let you tie to this lifecycle without being a real element.
10. Web Components, Lit, and Santa Tracker
Lit now has the concept of state versus properties. Design systems built with lit element and web components are being used by many companies. Santa Tracker showcases web components and supports legacy code. It's a single-page application with educational games.
So that's something you can read about if you are curious. Lit also now has the concept of state versus properties. Previously, it was all sort of mixed up together. But state is really useful if you have some database changes that you don't want to expose on the element. Which should still cause data mining updates.
One thing I find really interesting is that lit has been taken out and run with by a lot of companies to write design systems. Now design systems are whole suites of elements that you can just drop into your pages and get a certain look and feel. As well as a bunch of amazing new behavior. And so there's a whole bunch of these. You can look at any one of these pages and see a whole interpretation of a certain design system that you can drop into your pages that's built entirely with lit element and web components. We think that's really cool. These could be buttons, sliders, toggles, even whole site layouts that you can just drop in and use.
There's also some resources here if you are curious to find out more about lit. The website is amazing and it could do far more than I could give you in a talk.
Lastly, and perhaps most importantly, I want to talk a bit about Santa Tracker and how we use web components. Now, as I mentioned before, I'm the lead on Santa Tracker and I have been for many years. Santa Tracker works in a bunch of places on phones, tablets, even on TVs if we're lucky. It's a single-page application. It uses Web Components. And the goal for us really is to showcase new technologies, including web components, as well as supporting a lot of legacy code. The games aren't broken and we shouldn't throw them away. And they're still quite fun. So, some of those older games, they've been around for yonks and they'll hopefully stick around for a long time as well. Here's a quick demo. I want to show how the site works. You can't see where Santa is right now, because it's not December. If it is December, perhaps go to your other tab and check out where he is. But we can click on some games here and have a bit of a play. We try to focus on educational games, and we see this in tweets and photos we often see during the holiday season. We find a lot of classrooms do a lot of wind-down time and they want to play little games.
11. Educational Games and Web Components
A lot of our games tend to be educational, like Blockly coding games. We use about 40 Web Components, most of which inherit from LitElement. However, some vanilla elements are used for complex tasks like route animation libraries and interacting with unusual parts of the DOM.
A lot of our games tend to be educational, and this is something we really pushed on. The games are things like Blockly coding games and similar, that are quite fun in classrooms and are quite educational. We use about 40 Web Components. The vast majority do inherit from LitElement, but a small number don't. We find that the ones that don't tend to be ones where data binding isn't important. We often find that it's more succinct to write vanilla elements to do complicated things like route animation libraries or interact weirdly with parts of the DOM you don't normally touch, things like iFrames and resize observers and things like that.
12. Mix and Match, Showcase, and Awkward Elements
Mix and Match is intended in the platform to interrupt elements. Lit elements work well together regardless of how they are written. Showcase examples include Santa Card, which locks cards to a certain date, and The Elf Maker, which deals with complicated mouse movements and resizing. Santa Chrome controls the sidebar, mute button, and countdown. The Nav doesn't know it's the sidebar, and awkward elements like reindeer wrangler exist. Web components allow the creation of first class citizens.
But what I want to get down to is Mix and Match is actually intended, right? It's totally part of the platform to interrupt these elements in this way. Lit doesn't care that the element it's talking to is actually provided by Web Components. Lit elements don't care that other Lit elements are provided by Lit. So in many ways, we've got this great interrupt layer which makes these elements work really well together, regardless of how you write them.
Let's talk through some showcase. I've mentioned Santa Card before. One of the really cool parts of this in production is that we actually can lock these cards to a certain date. They subscribe to a global countdown, which, you know, when the date takes over, they magically unfreeze and open the game. We've also got this showcase of elements from my favorite game, The Elf Maker. So this is a bunch of choosers, right? You want to choose different parts of your elf to change or display or change the color of. What's really interesting here is that the choice element at the bottom, it doesn't really deal with data binding. So it mostly deals with, you know, complicated mouse movements and resizing and making sure these elements show up properly. So in this case, we have an inheritance from Lit. It doesn't make sense for us.
Next I want to talk about Santa Chrome. Now, Santa Chrome is a big element that really rewrites the whole page. It's not the Santa app. It doesn't do everything. But it's going to control the sidebar as well as the mute button and Santa's countdown to when it takes off, which is obviously very important. What I find super interesting is that the Nav doesn't really know that it's the sidebar. The Chrome element has a slot for the sidebar and when we place it there, whatever is in that slot will be shown when I press that button. It's a toggle. So we can test the navigation area or, you know, build it totally separately to whether show it on the page. Lastly, I want to call out, we do have some awkward elements too. We have this cute little element which shows a adult reindeer trying to wrangle a little reindeer who's accidentally flying away. It's got a silly name. It's called reindeer wrangler. It doesn't fit with anything else. So I want to leave you with some thoughts on web components. Why do we build web components? In the end, like I mentioned, you get to create first class citizens.
13. Web Components and Frameworks
We think web components are powerful and offer a wide range of options. You can create small widgets or go big with things like Santa Chrome. Web components are compatible with other frameworks and can be used almost everywhere. They have a zero kilobyte runtime. While using a framework like lit makes sense for most people, starting with web components is a feature you can just use.
We think this is really powerful. And your options are wide and varied. I've given you examples of creating small, you know, encapsulated widgets. Things like my details or maybe you want to bring back the blink tag or the marquee tag. You can do that with web components and that's fine.
You can also go really big and create things like Santa Chrome or pull in whole design systems which we think is really powerful. Web components are the interop layer, the interop layer with others. But frameworks are an interesting beast here. So other frameworks work differently.
LIT of course only creates web components. So we can create web components and we've seen some really cool demos of things like React and Vue with only like six or seven lines of code, turning their code into web components that can be shared with others. This isn't actually that common. What's more common is, can your framework use web components? And the answer is typically yes, because yet again, web components just look like HTML Elements. If your framework can work with HTML Elements and there's not too many overrides for some special cases, then turns out they don't care whether it's details or my details. My colleague, Rob Dodson, has this great article or this great website called Custom Elements Everywhere, which goes through a bunch of these use cases and shows off how different frameworks ranked and rate on this kind of scale.
Web components work almost everywhere. This is 95% plus of browsers and increasing. This basically represents all modern evergreens and is roughly equal to the set of browsers that support script type equals module, which for me personally has been such a great high watermark. I don't even bother shipping non-module code to browsers, or if I do, I'm going to send those users to a no or a low JS experience where, you know, lots of other features aren't going to work either. So I think this is really important to remember. This is a feature you can just use. Web components similarly have a zero kilobyte run time. This is not completely a fair statement. I have given you a few examples of how web components work, but I honestly think using a framework like lit makes sense for most people when they're getting started. This is a very similar analogy to service workers, which we shipped a couple of years ago and supported by all major browsers in a similar way. You can be very productive if you're a seasoned dev writing your own service worker from scratch. But for the vast majority of people, you're going to want to start with something like workbox. And that's fine. Right. It's not a concession.
14. Conclusion and Call to Action
I think it's a great way to start writing web components without getting too knee deep in the weeds of the nuances of all the boilerplate. Web components are a great thing here now. Go build some web components with lit. It's five kilobytes on your page. You can even just go to their playground and poke around and build some elements right there and there. Go make some elves dance. Santa Fe is a great place to have some delight.
I think it's a great way to learn and to evolve. And lit falls into that same category. I think it's a great way to start writing web components without getting too knee deep in the weeds of the nuances of all the boilerplate you're going to need to write an effective component on your own.
So that's it. I'm done. What I want you to take away from this talk is web components are a great thing here now. I want you to go away and build some web components with lit. It's five kilobytes on your page. It's not a huge amount of burden. And if you don't want to add to your page, you can even just go to their playground and poke around and build some elements right there and there. It's a amazing website that really helps you get started.
Finally, go make some elves dance, if you haven't already. Santa Fe is a great place to spend some time and to have some delight with your day. Thanks for listening.