Elliott Marquez talks with us about the history of Polymer and Lit, why you should pick Lit, working with web components, the shadow dom, managing state, and how Material design is built with web components.
Time Jump Links
- 00:19 Heeeeey there...
- 01:10 Introducing Elliott Marquez
- 03:33 History of Polymer
- 07:12 What's Lit's history?
- 08:42 Why would I pick Lit?
- 15:53 Converting fit-vids to a web component
- 17:49 Why would I grab Lit?
- 30:26 How does Lit work with the shadow dom?
- 32:07 Does Tailwind cause issues?
- 34:03 What's the design system and web components story?
- 42:26 How do you manage state?
- 50:34 Is Material design built in web components?
- 53:01 Password managers and shadow dom issues
- 54:53 Standards are not static
Episode Sponsors 🧡
MANTRA: Just Build Websites!
Dave Rupert: Hey there, Shop-o-maniacs. You're listening to another episode of the ShopTalk Show. I'm Dave--Malthusias, king of the Shadow DOM--Rupert. Forged in the fires of gook, carrying the sword of piecing.
Chris Coyier: [Laughter]
Dave: And with me is Chris Coyier. Hey, Chris. How are you?
Chris: [Laughter] Ah... I'm just a regular... I'm just a regular Light DOM Chris.
Chris: I ran out of creative credits. [Laughter] My brain just gave up.
Dave: Kind of stalled out, buffered, yep.
Chris: Dave, that's what rapid aging does to you, I'm afraid.
Dave: Yeah. It's how I feel.
Chris: Well, buckle your metaphorical seatbelts, people, or your non-metaphorical seatbelts if you're driving an actual car. Saving lives here. We're going to end up talking about all kinds of Web component-y and tangentially related stuff because we have a special guest on today, Elliott Marquez. What's up, Elliott? Thanks for coming on the show.
Elliott Marquez: Hello! Thanks for having me. It's about time. [Laughter]
Chris: I'll say.
Dave: This is our third or fourth attempt here, so we got it! We got it! We locked it in.
Chris: You know you can blame an actual squirrel last weekend. Here in Bend, Oregon, 18,000 customers without power, and the follow-up was like, "We think it was a squirrel. We think a squirrel did it."
Dave: [Laughter] That's great.
Elliott: Call it a free day off from work.
Chris: I was like, "Did you see a smoking squirrel or not?" How do you maybe think it's a squirrel? There was a power problem, and then you fixed it. What did you fix? Was it a wire that had squirrel bitemarks in it?
It seems weird. How do you not know what fixed it when there's a big power outage like that? I think they maybe just don't want to tell us. You know? Maybe it's a little--
But anyway, I didn't have power right as we were about to record last time. So, Elliott was very generous and allowed us to reschedule.
Sometimes guests are like, "Sure... Power outage. Mm-hmm. Mm-hmm." You know. Whatever. Then they're just like, "How about never?"
Elliott: No worries. I was at my parents' house. I was running off of mom's wi-fi, so it worked out for the better today.
Chris: Oh, nice.
Dave: Yeah. Mom wi-fi is great because it just mysteriously doesn't work throughout the whole house. It's just... You know?
Elliott: I swear it was fine until I was chatting with Dave. It just cuts out when you least need it.
Chris: Horrible. This one is going to be amazing, though. Elliott, you're at Google right now, right? That's the job.
Elliott: Yeah, so I am Elliott. I've been on the Lit team and the Material Web team since the Material 1 days and the Polymer days. Lots of weird Google org chart stuff going on there.
Chris: Yeah, you can talk about the whole... Oh, wow! Okay.
Dave: The whole journey, yeah.
Chris: Yeah, whole journey, indeed.
Elliott: Yeah, it's been fun. It's been lots of fun things getting the browser up to snuff to get Web components out to everyone and also working on design systems. That stuff is the next circle of hell, but... [laughter] No, I'm kidding. I'm kidding.
Elliott: Design systems just really make you care about things that no one else really cares about. You know?
Chris: Hmm... Well, we've talked about this trajectory, and you especially have, Dave, because Polymer has a sorted history and can occasionally be blamed for maybe people are less excited about Web components because that was so confusing back then. Despite being technologically interesting and whatnot, people are like, "Do I need this to use Web components?"
Anyway, we don't need to hash out that whole story, but the story is a lot happier lately. It's kind of cool that you're still there and get to roll in a happier era for Web components.
Elliott: Well, actually, I think it is actually kind of interesting to jump in on that a bit because we made a lot of mistakes back in the Polymer days. For one, Polymer actually co-launched with Material Design back in, I think it was, IO 2014. And there was a time where nobody knew what Polymer was or what Material Design was. Was it the same thing?
Then we started working with Web components polyfill, and then Polyfill are like, "Polyfill? Is that Polymer related?" It's like, "No, it's not."
Yeah... [Laughter] There were a lot of things that we did as a very, very young team. It was kind of fun, though, because we did work kind of as a startup within Google (in many ways) since we were under the Chrome org. The goal of the Polymer team was to bring front-end developers (not C++ browser developers) to help shape the Web and test out the Web component specs and prove them out.
Yeah, there's a lot of... We did make a lot of mistakes back then. You've probably heard the term "Use a platform" used quite facetiously over the last several years on Twitter. But what are you going to do?
Chris: Oh, even confused by that one because it sounds good, doesn't it? But then people are not necessarily speaking positively when they say that. I'm like, "Thanks, I will use the platform. That's my plan."
Dave: It's like, "Use the escalator." No.
Dave: Yeah, I'm going to use the escalator, guys. Okay, yeah. No.
Elliott: Honestly, I think we tried to turn Polymer into a product. We tried to ship 1.0 before the specs were ready. So, Polymer 1.0 actually shipped with a polyfill, like the Web components V0 polyfill, so the one that not all the browsers were ready on.
Elliott: Then the Polymer 1 to Polymer 2 migration was a bit hectic when we changed Polymer to follow standards. It was a lot of fun. [Laughter]
Chris: Was it conceptually two things? It was, like, okay, Web components are coming to the platform, but they're not quite ready yet, so this thing exists to allow you to do that now. And even when that happens, this does extra bonus stuff that makes them better. Right? Like an API to help you utilize them in a better way. I feel like those are two things, yeah, that are weird to smash together.
Elliott: Actually, Polymer was supposed to be what it was supposed to look like. Yeah, Polymer had Vue-like bindings in the templates. You had template tags, HTML imports, and the idea was that eventually we would get template binding a-la Polymer into the browser.
And so, theoretically, it was what we thought Web components would look like. Nowadays, with Lit, after we've learned a lot more and the standards are in, we've moved towards something that just makes it really easy to write Web components these days.
Chris: Yeah, right. Yeah, so Lit... Yeah, okay. Can you tell the same kind of story for Lit? It kind of turned into that or was it totally greenfield?
Elliott: Lit is basically Polymer 4.
Elliott: We have changed our tune a bit because it's quite a bit migration if you change from Polymer 3 to Polymer 4, mostly in terms of behaviors. There's no two-way data binding and stuff of the sort. But Lit--
We changed our tactic there. Lit, these days, is very, very, very, very easy to upgrade from one version to another. We are very incremental. We try to not change too many things to make sure that we adhere to the platform and stuff like that. We just released Lit 3.0, and most of the changes were dropping IE and getting ready for all sorts of stuff like template parts and stuff of the sort.
Chris: Okay. Okay. That's in the weeds with Web components a little bit. Let's say I'm like, "Oh, I love Web components. I listen to ShopTalk Show. Dave tells me they're the best. They're particularly good for design systems. They're good for isolated bits of componentry. I can even make one and ship to NPM if I want other people to use it."
There's kind of like this little checklist of reasons why they're kind of cool. Maybe you could help me expand that list a little bit and then say, like, "Let's say I drank that Kool-Aid. I'm in." Why would I pick Lit then?
Can you sales pitch me? I think that might be interesting on a podcast. You've been living this for a while. Your sales pitch better be pretty good. [Laughter]
Dave: I would like to also say I get asked this probably daily. It's people, "Oh, I want to learn about Web components, but I don't want to use Lit, so I'm going to learn Vanilla." And I'm just like, "Noooo!" I don't know. I'd love to... yeah, why? What do Web components do and why Lit? That would be good to know.
Elliott: Back in the 1990s, the Web shipped with a component system, and it's called and HTML element.
Chris: Ooh, spicy! [Laughter]
Elliott: Well, Web components are really just the component system that the C++ developers at the browsers have been using, and just opening it up for everybody. They've already been using things like Shadow DOM, so if you look at an input and go into Chrome dev tools and turn on user agent Shadow DOM, you could see an input has all these things inside of it and an actual Shadow DOM to it. Really, it was a lot of the browser engineers opening up the tools that they already used as developers.
Elliott: And so, yeah, Web components are the browser's native component model. Because of the way standards work, everything has to be backwards compatible and things of the sort.
When they made Web components, it integrates where kind of no other framework or library does. It integrates at the HTML level. You don't have to create a bunch of divs. You have to integrate at some sort of old frameworks rendering level.
Elliott: It actually integrates at the HTML level. You upgrade HTML elements, and it is... When you actually look into how everything works, it's actually quite beautiful how they fit in an entire kind of new paradigm of development into the existing Web.
But, yeah, that's more about the history. Web components today, I'm just going to say, are awesome. I'm a little biased here. But they have... There are a lot of competing things together, and they're really great. But sometimes you want something to work across all the things, and sometimes you don't. Right?
There are two use cases: the ones where you want things to work across all things. That's where Web components really, really shine because it's useful for a big company that is like, "I am a company that is large and acquires a bunch of small startups over time, and they all have different frameworks." You want to just create a simple design that works across all of them or just shared components across them.
Chris: So, you're not even talking about just browsers. Yes, it works across all browsers and it works across all frameworks.
Elliott: Yeah, it works across all frameworks because, what do all frameworks do? They render HTML. Where do Web components integrate? At the HTML level.
The way Shadow DOM works and with encapsulation, it just helps make sure that that doesn't try to interfere with anything. We can talk about that a bit later because it does interfere in some ways, especially on the server.
Chris: That does seem like pretty obvious just to bring it to the humble button, which is a classic design system kind of thing. I know we haven't really gotten into design systems yet, but you could do it once with a Web component. Despite you being at this enterprise company that's telling you that this has got to work across three, four different frameworks, boy, you did it. You made one and it works. As far as a sales pitch, it's a pretty good one.
Elliott: Yeah. Yeah, yeah. We've worked with teams like E Web Components Everywhere team. There's a website up called Web Components Everywhere. I don't remember the exact URL, but it's basically that. I don't remember if it has hyphens.
It really goes into how each framework interacts with Web components. Basically, can set attributes, can set hyphenated attributes, can accept something with an unknown tag name - and things of the sort.
Elliott: Every modern framework these days basically supports it. There are some parts of React that are missing it that are available in, I think, React 19 (it's currently slated). Who knows. If you still need to use React before that, we have actually helped solve that.
But yeah, so integrating with frameworks is one big thing. But I said there are two big sections. You need to support lots of frameworks, and the other one is the user that doesn't.
The user that doesn't, what they benefit from Web components are easy debuggability, easy to get started without build pipelines or anything of the sort, and just the simplicity that comes with using a browser primitive. No one is making a big deal about using arrays, right? [Laughter]
Dave: Yeah. Yeah.
Elliott: But E Web components, I see them as arrays. What evangelize about them is how do you make an array sound sexy to people? But yeah, the simplicity of Web components is that you can write one, a vanilla one on your own super quickly or you can use a library like Lit. Lit, we really love Web standards, so things of that sort, you can just import it with an esm.run link or the jsDelivr, and then just build to fit immediately.
Chris: Oh, gosh. Did you say esm.run? It just came up... Literally this morning, I was looking at it. It looks like JS delivers a version of pull something off NPM but have it be ESM ready.
Elliott: It reminds me a lot of Skypack. It does the bundling and stuff of the sort.
Chris: Yeah. Right. Skypack was great, but they've publicly said, "We're done," kind of.
Elliott: Yeah. Yeah.
Chris: And esm.sh is also very cool. But I think it's kind of an independent project. I've been using that a bunch. But yeah, esm.run is just jsDelivr, who is kind of a bigger name. They've been at the CDN-hosted NPM package thing for a hot minute. That's cool.
Yeah, and this conversation just started saying that, "Yes, you could make one with Lit," or whatever. But you probably do want to use some framework. Right? We should talk about that.
Then put it on there. Then if I want to use your emoji picker - or whatever it is - I just can pluck it off and use it. How satisfying.
Elliott: Yeah, that's the goal. But yeah, one note on esm.run with Skypack, I love esm.run because it's a successor to Skypack, but it's just missing Fred in there.
Dave: No, Fred. No Fred.
Elliott: ...on the Polymer team and miss the guy.
Chris: Oh, yeah. There's kind of a direction connect there, isn't there? Yeah.
Elliott: Yeah, yeah. He was there for a hot minute since we launched.
Dave: This has been Fred's long game the whole time is getting people to use elements. Yeah, well, it's worth noting I converted my old jQuery library (FitVids) to a Web component last week, so you can now use get FitVids, Daveatron5000/fit/vids - or whatever, from NPM. Please don't use it.
I got a bug report for the old jQuery thing, and I was just like, "I don't... Don't use it." You know? This is so old and not--
Chris: Max width 100%, aspect ratio 16:9. Done.
Dave: You could do it in CSS, and the only reason this needs to exist is the Web component form is just purely to have non-16:9 aspect ratios automatically generated. It's an aspect ratio generator.
Chris: Oh, does it pull the width and height off the video tag and promote them to the aspect ratio property?
Dave: Yep. Yeah.
Chris: Oh, well...
Dave: Yeah, that's all it does.
Chris: I've seen dumber. I've seen dumber.
Dave: Well, and it's vanilla because it's literally 800 bytes, 600 bytes - or something like that.
Chris: Oh, you didn't even use Lit because you needed no assistance.
Dave: Zero assistance. I mean it doesn't even... I'm calling super, like connected... constructor super, but I don't even think I need that. I think I'm not doing anything.
Dave: I'm just a pretend element. But anyway, I'm curious in this progression. We've talked about old Polymer, HTML imports, rest in peace. Killed by Mozilla. We'll never forgive. Never forget.
Chris: Oh, I'm very interested in this because I actually don't know. I used Lit a few times, and I always forget. Why am I doing this again? Yeah, here we go.
Elliott: Lit. Let's start with Lit. The progression of Web components was, we built Polymer with the Web components V0 spec. Then once it became standardized, the standards committees thought we should actually maybe focus on ES Modules as the module system rather than HTML imports because, at that point, you already have CSS import modules like we have @import in CSS. You have ES Modules, and now you're introducing another tree of loading things. And it would complicate quite a lot of things and mess up performance and stuff. All sorts of stuff of the sort.
Honestly, I love HTML imports, and I love the idea of them, but I feel like there were some issues. Every time you HTML imported something, it was in the global scope. Like if you had a script and did window.whatever, it would affect window everywhere.
Dave: Oof, yeah.
But yeah, with that, we created Lit using literals, template literals, and that was a way to do templating without having a transpile step like for JSX or something of the sort. We wouldn't be opposed if JSX became a standard in the browser. We'd love to work with something like that. That'd be pretty cool. But currently, template literals are pretty good.
I'm sorry. You'll have to remind me about the second question.
Dave: Whenever people say, "Oh, let's put JSX in the browser," I'm like, "Have you seen HTML tag template literals?" [Laughter]
Dave: Well, yeah. Just to make sure, you have seen that, right? It's backticks. You put HTML in there. You're 90% there. You know?
Dave: It's pretty much JSX.
Chris: It's not as strict, though. You know? I do kind of like how mean JSX is and how well it works with Prettier, for example. Love Prettier. Okay, so--
Elliott: Tag templates worked with Prettier as well. Just so you know.
Chris: Oh, do they?
Elliott: They're very well done. They did a lot of wicked work there.
Chris: Oh, as long as it's tagged.
Elliott: Yeah, as long as it's tagged with the language.
Chris: Okay. Yeah, that's good to know. All right, but I'm writing my component.js, so I write "class my component extends LitElement," right at the top, the first line.
The question was kind of like, "Why? What do I get? Why is this better?" It clearly is. I like to have the checklist in my brain. I like to know when I'm going to reach for the tool because I have the checklist so clearly mapped out.
Elliott: Currently, Web components are quite low-level. They're very imperative and require a lot of boilerplate to get some things done, such as HTML attribute reflection and turning those into properties. It doesn't do that by default, but it'll give you an attribute watcher and stuff like that.
Chris: Okay, so now I've written
Elliott: Yeah, there's quite a bit of ceremony. You have to do the static observed attributes property, and say you wanted to list color, and then the attribute callback. And when the attribute that changes color has a change, set the property, and things like that.
Elliott: Lit just makes that super, super easy for you. A lot of people say, "Well, why did they make something so useless that requires so much work, and it's imperative, and it doesn't work with the server?" I think the goal of Web components has always to be declarative. It's just a lot, lot easier to build the imperative part first. And standards, they're a shark. They keep moving forward. They're always living.
Yeah, Lit is there to make it easier to write Web components get around that ceremony.
If I change that property, which you could do with any technology, I need it to change. I need it to change from my grid template to my columns template or something. It's going to do something in my component, so you have to be watching for changes on that. Wonderful. Which a framework might do, too, right? You're using this within Vue. The value of that attribute might be a variable that changes. Okay, that's the first one.
Does it do something for me with CSS? It does a little bit, doesn't it?
Elliott: Yes, so it basically, automatically, hooks up the constructible style sheets with your ShadowRoot. It creates a ShadowRoot for your element. For people who don't know that, it creates... a ShadowRoot is a sub-document inside of your application, I guess a document tree. And it can scope query selectors. It can scope CSS rules and all sorts of stuff inside the ShadowRoot.
You have a custom element at the top. Lit will attach ShadowRoot to it. And ShadowRoot, by default, scope styles. But how do you apply the styles in there. You can do a style tag or you can do a constructable style sheet.
Chris: Oh, yeah. That would be nice. It does make me think, "Okay, I'm just going to use a style tag. That's just so dumb. It's a no-brainer, easy." But let's say there are 40 of these Web components on the page. I don't know if performance is a huge concern or not, but it does seem like it would have to be parsed 40 times and applied 40 times, whereas a constructible style sheet is kind of sitting in memory already, already ready to use.
Elliott: Fun fact: I think I've looked this up in the Chromium source at one point. When you put a style tag in a ShadowRoot, and you put the exact same style tag with the exact same text in another ShadowRoot, the only thing that happens is that the HTML parser will go and read the text, and the HTML parser is very, very fast, so it'll read the text of it and then be like, "All right. That is a style sheet." It goes to the next one. It reads the text. It will do the exact same thing as using link rel href. It'll be the exact same cache and pull from that cache and then just reapply it there.
Chris: How clever, clever. So, it really doesn't matter that much.
Elliott: Yeah, it doesn't matter too much. But you know littering your... The HTML read still is none zero work, and we are perfectionists here. [Laughter] We want to make sure performance is top-notch here.
Chris: Yeah. It does seem... As an author, that's what I want. I'm just one person, so who knows. But I do kind of want to be like, "See that CSS over there. That's the CSS for this Web component," in a file or something.
Elliott: [Laughter] Yeah.
Chris: Any one of these things, it's like, "Just write it with all the rest of the crap in there. Make a big ol' tag template literal with 80 lines of CSS in it." I'm like, "No! It's gross." [Laughter]
Elliott: The great thing about adopted style sheets and constructive style sheets is one of the big issues these days with Web components, people are like, "I just want to use Bootstrap in my Web component. Do I have to really just shove the entire style sheet in there and whatever?"
Elliott: Theoretically, you can have multiple components import the exact same CSS file. Then you get that cache between each of them. Whatever.
Dave: No double download penalty going on, right? Yeah.
Chris: What does that mean? If it's a tag template literal, can I do the dollar sign, squiggly thing, and then make color equals color attribute? I could do dynamic-ish things in that tag template literal?
Elliott: Well, because we're a library at Google, we have an excellent ISE, the e-security team that makes sure that we don't do that. [Laughter]
Elliott: You can't do that, so you could interpolate static other CSS backtick things into it. But for security reasons, it's that. We do have an unsafe CSS directive that you can just write whatever you want in there.
Elliott: But yeah, you can do that. We don't necessarily recommend doing that. We recommend, like if you want to share a variable across things, we don't necessarily recommend doing that. We recommend using CSS custom properties.
Chris: If I was going to set a primary color for a Web component, color=purple, I could (in the constructor or something) ultimately do whatever it is, this.ShadowRoot.document.style.set-attribute, or some incantation that sets that custom property at the ShadowRoot level, so it can use that color purple in the CSS via the custom property?
Elliott: Well, the good thing about custom properties is that they can actually cascade through the ShadowRoot.
Chris: Ah, right. I don't even have to bother setting it at the ShadowRoot. Just set it on the element itself.
Elliott: Yeah, or the root page, whatever you want. What we've done with the material Web library, which we just released, it integrates Material 3 or is colloquially known as Material U. It has the dynamic color system and all that amazing stuff.
Elliott: And the way we implement Material's token system is the CSS custom properties. You have all these buttons, all these whatever on a page. You can just say --md-sys-primary-color... Oh, color-primary. Sorry. It's not like I work on the team or anything.
Chris: Yeah. [Laughter]
Elliott: You set that to red or something like that.
Elliott: It'll change the primary color in everything to red. It's actually really great. You get into a really nice flow of using Material CSS custom properties and just building your app with it. I do wish for a bit more, but--
Chris: That's nice. CSS custom properties can penetrate the Shadow DOM and, just because of that, it makes someone really a pretty nice pairing with Web components in Shadow DOM, right?
Elliott: Yeah. Very few things can penetrate the Shadow DOM. It's mostly inherited values like CSS properties.
Chris: Yeah, like your font family or whatever still comes through. Right.
Elliott: Yeah, font family and things of the sort like that because, if you could do it to an input, you can do it to a Web component mostly.
Chris: Oh, yeah. Right on. Or just don't use Shadow DOM, right?
Elliott: Whatever floats your boat.
Chris: How do you do that in Lit? It's kind of Shadow DOM by default and then you turn it off?
Elliott: Yeah, it's Shadow DOM by default. You can override... There's a callback. A kind of offer that I can't remember the call off the top by name, but instead of attaching ShadowRoot, you just return vis, which is the element itself. It'll just attach things to the thing.
But in that case, we don't know what to do with the styles, so you have to handle styles yourself, however you're going to do that.
Dave: Or just use a global style sheet, right?
Elliott: Yeah, but again, one of the beauties of ShadowRoot and Shadow DOM is that it is a way you can actually package styles with a component that works across platform because right now you kind of have to just... How do you package styles with a component these days? Every framework has its own weird way to do it. But this is a standard way to just do it together and package it.
Dave: Does Tailwind present any challenges here? Utility libraries has been huge stuff for the last five, eight years. People who are using Tailwind and Web components, what are they doing? Are they just generating a CSS File per component? Are they just importing every gig of Tailwind? What are they doing to make that work in a utility library world? I use utilities, but not to the extent of Tailwind, but how would you do something like that?
Elliott: I'm going to be a bit honest here. I've been really darn into the material world right now.
Elliott: I love Tailwind, what it's been doing, but I'm a bit ignorant on some of its things. But I do know utility libraries in general, like Bootstrap and Tailwind... Well, not necessarily Bootstrap, but you know.
Dave: Yeah, well Bootstrap has--
Dave: Yeah, it has utilities, too.
Elliott: Yeah. A lot of them are written in a global sense where the style is not really written in a modular manner. But the users have found ways, especially with import attributes these days, to share these.
A lot of times, I understand people just import the style sheet from all sorts of things using import attributes or some build time transform to turn it into a CSS-backed literal.
Elliott: There is a wonderful community. There is a wonderful community member. His name is James Garbutt, and he just released an article very recently on using Web component Slit and Tailwind. And unfortunately, that's really all I can speak to. I've really been heads down in Material work recently.
Dave: Well, that's probably a good segue. Material is a design system, Google's design system, built entirely with Web components. One thing I hear about Web components, when I talk about them, people go, "Yeah, they're great for that, but not for design systems. I work on serious stuff," or whatever.
What is the experience of building a big design system that serves a lot of products like YouTube-level crud here? We're not baby products or whatever. How does that work with Web components? I'm curious. How do you do composition? How do you do shared state? Is Shadow DOM a problem? [Laughter] Because I could see it being--
Elliott: Is Shadow DOM a problem? More at 9:00.
Dave: Is Shadow DOM influencing your children? More at 9:00.
Chris: It's starting to feel less and less cool, but it might be just in the air. Go ahead.
Elliott: Yeah, so hopefully Shadow DOM feels less cool, and hopefully it's just a boring thing that everyone uses, like an array. But yeah, so I've been maintaining some sort of official Material Design implementation from Material 1, 2, and now 3.
Back in the Material 1 days, it was the Polymer paper elements. The first implementation, actually, because again it's the silly co-launch that we did. I've actually supported YouTube themselves using those components. YouTube is still written in Polymer. They should update.
Elliott: Yeah, they have some.... We've learned a lot through the time, but we've learned a lot recently on how Web components are a really, really good tool for design systems, specifically because of maybe how Google works.
Google is a big mono repo. So, if you make a change to the repo, you have to fix everybody's tasks. So, when you're a core system like the Lit team or the paper elements team back in the Polymer 1 days, you make a change to a component and it affects literally thousands of engineers. You have to fix all their tasks and things of the sort.
Back then, we relied a lot on the... CSS mixins, back in the day where anybody could just apply a mixin at runtime and just change any node in the Shadow DOM however they wanted to. We used to do all sorts of slotting because Shadow DOM had slots, so users could put arbitrary HTML in there.
What we've learned is being very, very open like that is quite difficult for a case like Google. You make a change. One of my things was, you know how a material input has that line at the bottom?
Dave: Mm-hmm. Mm-hmm.
Elliott: Some people tried to hide the line with opacity zero, some display none. Some of them did order height or border width zero. So, if you need to change the color or change that from a border to a background color, then you start running into all sorts of things because Googlers are very clever people. They do the most weird, random shit. Pardon my French. [Laughter]
You can do host styles, like style the actual element itself. And you can only style the things that are exposed to the :host selector. You can do things like inheritance using CSS, the inherit value. And there are bigger ... like CSS Shadow Parts, which we restrict within Google.
And what other stuff? Oh, you can also subclass the element and just inject your own styles, which again we restrict at Google. But external, GitHub, none of this stuff is a mono repo. Those restrictions don't necessarily need to apply to users.
Chris: Does subclass mean like Material Design exposes some input element? I'll extend that and change it, so I'm not changing the orig--? Oh, that's interesting. I didn't even know you could do that.
Elliott: Yeah, so the way we structure our components is we write all of our logic in certain classes, and then we have another file that marries the class with the styles and then does the custom-elements.define-call. Theoretically, users outside of Google (because we restrict this internally) can just import the class, the underlying class, and change the styles.
Chris: Yeah, that makes sense for us. I get why you restrict it, though. You're like, "What's a design system if anybody can just override anything?"
Elliott: Not just that. What I'm trying to get at is that it's very important for maintainability and for making sure you have a very clear, defined API where people can use and externally allow an escape hatch. Externally, we say subclass when you're doing all that stuff. We may break you. Use it as an escape hatch. But if you're using that, then you should probably file a bug on us. It's probably something that we should expose to you.
But internally, you can have very measured approaches on how to upgrade an element or how to change something because you have a very defined API for CSS slotting and all that stuff. Design systems as Web components are actually really, really useful in this case because we have other teams... there's another sister Material team that does our internal framework called Wiz, which it does a traditional manner of you write a template, it creates a component, and you have to follow these rules to stay within these scope styles. And they're having quite a lot of issues with users still styling things globally and things of the sort. It really makes their work grind down to a big of a slog.
Yeah, if you're external, you could just basically do whatever you want. We may break you, but you should really file bugs on us. But if you stay within the thing, if you stay within our API that we've defined, then you can rest assured we have migrated people making changes to that API, so if you stay on that and there's a breaking change in the future, that breaking change is going to be pretty well thought out on our end because we don't want to write a lot of code for migrating people at Google.
Dave: That's cool. It's like, if I'm thinking of it right, it's like class MDS (Material Design System) button, MDS button extends base button - or something like that. Then I can combine, say, class Dave button extends MDS button, or I can just extend base button myself and make my own abomination. Yeah.
Elliott: Yeah. Yeah.
Dave: Very cool.
Elliott: Yeah. We do work quite a lot. Another reason why we want to keep our DOM scoped is we work quite, quite hard to make sure accessibility is up to Google standards. We have Google accessibility rating internally and berated. We periodically meet with Material Design accessibility engineers who do audits of our code and make sure it's up to screen reader potential and high contrast mode and all those sorts of stuff.
Dave: Cool. I'm curious about that. What about state? There's no redux in Web components, and there's local component state. Just variables that get updated. But how does Google do redux, global state sort of things?
Elliott: Well, in particular with our components, they are basically leaf nodes, so they don't actually have much state associated with them. They really much follow the props down, events up situation where if you just follow the standard, durable elements on the page like an input does, you'll be generally fine because everyone is built for an input before.
Internally at Google, everyone uses all sorts of things of whatever they want. People that build with Web components, they either use a MobX or redux or things of the sort. And if you're an Angular or Wiz user, you use your respective state management libraries and then just integrate with Web components as if they were just elements.
Yeah, Lit does have some state solutions. We have an official redux implementation. Wait, is it redux? Sorry, no. We have an official context implementation, which is good for very, very basic state. But Web components and most Lit components are just a TypeScript file, a general TypeScript library. You can integrate usually whatever state you want.
We've recently promoted our Signals library, which uses React Signals. It's more of just a reference implementation. Theoretically, you can write it with any sort of Signals library you want.
Chris: Got to hop on the Signals train, though. You know?
Chris: I mean I know Angular is on it and whatever. I'm not trying to--
Dave: You double your funding if you have Signals. It's easy.
Elliott: A lot of the times we just have to be able to show that it's possible with Lit, and people can create their own integrations.
Elliott: Signals are pretty cool. I don't know if they're completely necessary for Lit because Lit is very, very fast on its own and Signals provide maybe just a marginal increase in performance. But people have infrastructure that have Signals. It would be good to make sure or enable our users to integrate with something like that.
Dave: That's, I think, what's interesting about Web components is they have this idea of attribute changed. That's baked into the system. And so, if I just update the attribute on the component, it will trigger it's own force update or whatever you want to call it. It'll trigger its own update, and that's pretty interesting. You get that for free, kind of. You know?
Elliott: Well, attribute change just really calls the attribute change callback, and then it's up to you to create whatever, do whatever you want with that. You can do something that just directly modifies the DOM, or you can create a lifecycle such as how Lit has done it.
Dave: Yeah, and I would use Lit because Lit's render method is convenient.
Chris: Yeah, all right, so there's a render method as part of Lit elements that returns a tagged template literal. That way if data changes, you're not on your own to re-render. Right? That's the point of the render method. Is that right? You get that, like, obviously, you want to re-render this thing, right? The data changed. We got you.
Elliott: Yeah, so if you call the tag template literal with the exact same values in Lit, it will just basically be a no op.
Elliott: The tag template literal, again, isn't a string in Lit. It creates an object. In the Lit 3 presentation that we just gave about a week ago -- maybe several weeks when this episode comes out -- we actually are talking about our Lit compiler. And so, the Lit compiler is an optional compiler that just pre- does that initial work for you in the template.
When you first run a Lit template, it returns an object that is just metadata of where the bindings are. And the compiler will just go through your TypeScript source and just do that initial step for you.
Chris: A little faster when you ship it.
Elliott: Yeah, well, we've received some numbers in our benchmarks like up to 40% increases on very large templates.
Chris: Oh, nice. That's what makes this kind of surgically faster, right? Maybe with your own Web component, if you had some data change, you'd just be like, "I just need to change the entire chunk of HTML because I don't have any smarter way to do that."
Elliott: Yeah, there are multiple ways and multiple things to this. So, yeah, it keeps track of exactly where things are in the template and updates those surgically. But the other thing is that each Web component or each Lit component has its completely own lifecycle separate from each other. If you update this element and it doesn't affect any of its children elements, doesn't change any of their properties, only that element will update, that template will update. It's already distributed and stuff like that.
Chris: Mm-hmm. Cool.
Elliott: So, when you come to Signals, again Signals are point-based changes and already our templates update the template itself, which is a bit more than that. But again, our Signals implementation also can do the point change update if you want that as well.
Dave: If I have my card and inside my card is my button, and I change an attribute or something that changes my card, only my card will re-render? My button stays the same?
Elliott: As long as you didn't bind something to my button that will cause my button to re-render. Yeah.
Dave: It does a donut, like donut rendering.
Elliott: Yeah. [Laughter]
Dave: That's incredible.
Dave: I feel like that's a very... People... I'm like, "Oh, Lit HTML is pretty good." [Laughter] It's JSX in the browser already. But I think this is an under-marketed, undersold feature of Lit. It actually does this autonomic updating, and that's been since Polymer had that, too. It does this atomic updating really, really efficiently.
Chris: That was the first thing. Remember old-school React when React first came out? It was like, "It's got the Shadow DOM, and it only updates the tiniest little piece of DOM that needs to be updated." And everybody was like, "Yay! That's so cool!" And it is kind of cool. I know that story has changed over time, but that's what Lit is doing here, only it's even better at it because--
Elliott: I think you meant to say the virtual DOM, not Shadow DOM.
Dave: Yeah, virtual DOM.
Chris: Oh, yes. I'm sorry. They did not. Yeah, they don't mess with the Shadow DOM, the VDOM.
Dave: But I don't know. That's pretty incredible - whatever. You get into it, like rendering the whole tree. Doing the whole tree is expensive. Doing just part of the tree is fast.
Elliott: In the virtual DOM world, there's been a lot of good work to kind of get to a Lit-like state, like Million JS, I believe, works in kind of the same way where it tries to just find the points where things are changed. I think it kind of does Signals in a way or I think it's more Lit-like.
Elliott: I won't talk more about that...
Chris: I never quite understood. Isn't there a point at which your application can use that, but you might think about it a little too much, like, what if a little bit of extra HTML gets re-rendered? Is that the world's biggest problem in Web development?
Elliott: Not really.
Elliott: But you know, as framework and library authors, we really want to make sure that we don't give you a foot gun.
Chris: Yeah. Yeah. Yeah. That was a lot of stuff on Lit. Do you want to talk about Material Design, too? The biggest question on my mind is--you work on both--is Material Design--? I think Dave said it earlier. It's straight-up built from Web components. I didn't even really know that. Is that--?
Elliott: Yes. Material Design, again, is a design system in terms of a bunch of designers thought of how it could look. The Material organization, we have several implementations. We have the Android version. We have an iOS version.
We moved... After we got a lot of the standards done, we wanted to move away from Chrome into being more of a product itself, so helping unify a Material Designs Web approach. And so, the implementation that we just released, we just 1.0 it, is our Web components implementation of Material Design 3.
We had a Material Design 2 version, but Material 3 came out kind of late. There was a little caught up in the reorg, but Material Design 3.1 is built with Web components and it's great. Everyone should check it out.
They're form associated. They are very accessible. Probably the most accessible menus that you could find.
Chris: What does form associated mean? I can use your input element in a form and it will behave like a native input will behave?
Elliott: Yes, so you know there are many approaches to building an input or a button. It's like you've got to use an input or the button inside your Shadow DOM. But the form does not go into your Shadow DOM. There were hacks that you could do before, but what we do now is using form associated custom elements, which is a recent standard on associating and telling the form that this my-input is an input.
Chris: An input?
Elliott: It is a form control. There's lots of cool stuff. It's quite bleeding edge, and sometimes it's called bleeding edge because you bleed sometimes, but you know. Got to make sure we get all that stuff out of the way.
Chris: That seems pretty huge, though. Yeah, that seemed like... Because you're like, "Oh, what could I use Web components for? Oh, how about I make all our form stuff that way? That makes it really nice to do styled forms." Then you're like, "Oh, just kidding. Those don't participate on forms." You're like, "I'm sorry... What?!" [Laughter]
Elliott: There are still some problems. Currently, password managers can't reach into Shadow DOM.
I've been working a bit with--I've actually got to get back to them--the 1Password team to see if we can create a community standard for password managers to integrate with Web components.
Chris: I don't want to dwell on that, but that seems like a big deal. If I make my password form a material input, 1Password won't work on it?
Elliott: Yeah, unfortunately, not yet. I have been working with 1Password trying to see if I can reach out. If you run a password manager, reach out to me.
Elliott: Lit.dev/discord. There are some issues like you can do Light DOM passing through....
Elliott: Or inputs. That should just work. But currently, we think this is the best approach to building the component for material text field. We're just going to work and try to make the standards, the community, and the greater Web better instead of just going back to fallbacks. But yeah, Material components are great. They have SSR, basic SSR functionality and stuff.
Elliott: They're fun, lots of fun.
Chris: Yeah, right on. Can I piecemeal them, too? It looks like they're on NPM, right? Just pluck it off and they tree shake and do whatever you want?
Elliott: They're on NPM. They'll tree shake. We also have this big ol' import that's just all .js, so that's really good for esm.run because esm.run will bundle it in the cloud before it serves it to you, which is not necessarily good for individuals using esm.run for individual components because they may bundle multiple versions of the same Web component, which is another issue in itself. But I don't know how much time we've got for that. [Laughter]
Chris: Yeah. I don't know. But you've... There's a lot of Shadow DOM help, a lot of Shadow DOM going on. It sounds like you're a fan.
What I like about it is that it is unique entirely to Web components, your access to it and your ability to use it, which no framework will ever be able to do that. React can't ship their version of the Shadow DOM. That's not a thing. It needs to be a Web platform feature, so that's pretty cool to have access to it.
Yet it does present a number of weird problems. The forms thing and the CSS thing and never been the biggest fan of the styling story because of how tricky it is. It's just anything but as simple as just applying some CSS to the page. Anyway, there's some issues.
I don't mean to do anything too spicy here, but is there a world of Light DOM just getting really cool and people just being like, "You know what? Forget all the Shadow DOM. I'm going to use everything about Web components except for that"?
Elliott: Well, Light DOM already is cool, isn't it? You have all sorts of frameworks building exclusively with Light DOM. I think it's already great. I think the best part here is to actually improve Shadow DOM. Right now, it's very good to get declarative Shadow DOM. You can SSR it and everything nowadays.
But you know standards are not static. They're always evolving. That means Web components will always continue to evolve. But the way standards evolve is that they evolve slowly, very meticulously, and in a backwards compatible fashion.
Elliott: You write a Web function today; it should be there tomorrow.
Chris: Is that what you meant by the tide lifts all boats thing? Is the standard the tide?
Elliott: Yeah. Yeah, yeah, like HTML template tags were created for Web components, and it's just the fastest way to clone DOM out there. Every framework uses it these days. Yeah, and HTML imports were tossed out mostly for ES imports.
You know there's the entire thing with DHH talking about build-less development. No matter how you feel about DHH, [laughter] the idea is maybe that's not for you but making build-less development better makes it such that you get things like Vite or esbuild or things that start using native ES module imports and stuff like that just to make those tools even better themselves.
It's like you work... Web components, I feel, kind of are the NASA of the Web. We made memory foam. [Laughter]
Chris: You did just ship a compiler for Lit, too, which is a build thing. But are the ones that you grab from NPM - or whatever - are they prebuilt in a way? You don't actually have to run that compiler because they already have been compiled?
Chris: Ooh... Google-wide? That's a Google maxim from the top?
Elliott: Yes, it is.
Chris: Oh, my gosh.
Dave: Sundar? Sundar?
Elliott: Yeah, he's a big ol' TS fan. [Laughter]
Chris: Sure. But the compiler is then there for the ones that you write.
Elliott: So, the Lit compiler is something meant to be used as an optional step. It's not required or anything. It's just if you want free performance at the expense of maybe larger binary bundle size.
But it's there for optional use at the application level, and you don't need it. [Laughter] Don't recommend you compile your components before you send them out.
Chris: Oh, okay.
Elliott: Because when you start compiling things before you publish them, if you run into bugs, debugging becomes a lot harder. And Web components are uniquely good at being debugged because they are actual elements in your inspector, and you could just $0 property value, unlike other things.
Chris: Yeah! Oh, that's a good point to end on, perhaps. Uniquely good at being debugged.
Elliott: Yeah. [Laughter] We have a lot of jokes where it's like the Web components dev tools are just called dev tools.
Elliott: But there actually Web components dev tools.
Elliott: Lots of wonderful community members out there. The same thing with the MDX for Web components is just MD.
Dave: Yeah. That's my favorite. I have a blog post written about that. It's just Markdown. You just put Markdown on the page and it works.
Well, that's very cool. I feel like we've learned a lot. I've done a lot of Web component work. I've done a lot of design system work. But I've never combined the two, like in a big... But I'm feeling more... I know y'all are doing it. I know Brad Frost has kind of bought in on it.
I'm feeling more bullish on the idea that it's possible without losing my hair and gaining 50 years. But I think that's very cool to see just how a big company like Google would do it at scale. I think I learned a lot.
I guess we'll have to wrap it up here. For people who aren't following you and giving you money, how can they do that?
Elliott: [Laughter] I'm @techytacos on Twitter. I suggest you go to lit.dev to learn more about Lit. We have material-web.dev if you want to learn more about the Material Web library.
Elliott: That website is still a little bit under development, so check the GitHub as well.
Dave: Nice. Then there's also, yeah, the Discord is pretty happenin', too. It's a good little place to be.
Dave: There you go. All right, well, thank you so much for coming on the show. Thank you, dear listener, for downloading this in your podcatcher of choice. Be sure to star, heart, favorite it up. That's how people find out about the show.
Follow us on Mastodon this week. Then Twitter is still grounded. [Laughter] Then join us for the real party, patreon.com/shoptalkshow for the D-d-d-d-discord.
Chris, do you got anything else you'd like to say?
Chris: Oh... ShopTalkShow.com.