Eric Bidelman: Web Components
[32:39]
transcript
ERIC BIDELMAN: Welcome, everybody. Thank you so much for coming to Web Components. You're going to learn a lot in the next 40 minutes. Thank you to everyone-- [APPLAUSE] ERIC BIDELMAN: I haven't started it yet. You guys, you guys. You might not learn anything. You don't even know what I have in this slide deck. So a little bit about myself, so you know who's up here in front of you. My name is Eric Bidelman. I work on the Google Chrome team. I'm on the developer relations team there. We're going to talk about a lot of stuff, so there might not be enough time for questions. Feel free, please, tweet at me, Google+ me, come poke me afterwards at Office Hours. So I have 40 minutes to cover the future web platform, which is a complete fail. We could talk about this for three days straight. There should be a conference devoted to Web Components. There's so much stuff now that's starting to even land in browsers that it's just amazing, and I fundamentally think it's going to change the way we think about developing apps. This is what you're going to feel like for the next 40 minutes. We're going to throw a lot of stuff your way. Boosh! And then hopefully, around that 35 minute mark, you'll have this moment of zen. Hopefully some of this stuff will make sense, and you'll really see where this is trying to go. So if you've been following Web Components, or this term Web Components, even at a sort of bird's eye view, what the heck are we talking about? Well, we're talking about custom elements in HTML. You can define a new vocabulary for HTML. So the blink tag, for example, is not dead. The blink tag is alive and well. We can call it x-blink, and all it is-- it's a custom element that I've implemented using CSS, and it just has an opacity change using transitions. That's kind of a silly example. But you can do something like the gangnam-style tag. [MUSIC - PSY, "GANGNAM STYLE"] ERIC BIDELMAN: And that's all it does, right? A CSS action. So as a user of this component, all I have to do is include the gangnam-style tag on my page, and I get-- [MUSIC - PSY, "GANGNAM STYLE"] ERIC BIDELMAN: Of course, there's more practical examples, and maybe this one's not practical either, but it's not just defining new elements in HTML. It's actually extending existing. If you don't like the way the native HTML button does its thing, you can say a button is a mega-button, and define that mega-button to do something like on a CSS transition, have this crazy gradient, and then when you click it-- [MOO] ERIC BIDELMAN: It moos at you. So defining your own, extending-- you'll see some more practical examples, but that's what this is all about. Being able to expand on what we have in HTML. So when I think of Web Components-- so this ecosystem, this umbrella terminology for new stuff-- I think of four main areas. I think of Shadow DOM. This is sort of the foundational glue, the mortar, this is how we get encapsulation for free on the web. HTML templates. So if you're going to build a custom element, a widget, a component for your page, you need to be able to scaffold out sort of inert chunks of markup, and then use those later as people stamp out your element. Custom elements brings all this together. This is how you define a new tag in HTML and put all these lower level technologies together. Think of that as your Bat utility belt. And lastly, HTML import sort of is used for repackaging, repurposing. If somebody writes this awesome component someplace over on the web, throws it up on a CDN, I can then import that into my page and reuse that. So we have now this proper notion of reusability on the web, which is awesome. So all in all, a collection of new API primitives in the browser. That's what I think about when I hear Web Components. And we'll talk about each of these in this presentation. So 40 minutes, and I have 36 to cover all this stuff. So HTML templates is the first beast. This is really cool. With one tag, we now have proper, like, at the browser level, the ability to template out a certain section of markup to be a template. And this is great, because what you put in this is just DOM, right? So I'm working with DOM, the browser knows DOM, it's easy to work with. That's really awesome. But the best part about template is that it's parsed and not rendered. And basically what that means is that things like scripts are not going to run. If I have a script tag in this template, it's not going to run until I actually stamp this template out and use it. So that's really cool. Stylesheets and images aren't going to load until I stamp this template out. So that's great from a resource perspective. You're not loading things in. If the user never sees this template-- maybe it's a view or something-- you're not actually going to waste bandwidth until you use it. And media's not played. So if you had a video in here that had autoplay true, that's not going to do anything until you actually invoke and stamp this template out. The other really nice property about the template element is that it's hidden from the document. So that basically means you can't traverse into it. It's in its own separate little world. So for an example, if I try to query selector in and try to rip out that comment div that I have in my template, I'm not going to be able to do that, because, again, it's in its own sort of context. So it truly is a template that you can use and reuse. And so how do we use a template? There's two ways. The first is there's a content property on the template element itself. And that'll just give you a document fragment. So that'll just give you a chunk of DOM you can work with. And the second is, if you want, you can do innerHTML and work with that. So the process for using a template-- clone it, grabbing that content in any way you want, stamp it out, and then that's what activates it. That's what makes the stuff inside of it go live. Then you see what's in it. So by default, it's actually display none, right? So a quick example. I have the same template that I had before. Just a blank source and an empty comment div. I can rip out the content property. And this is a great example of showing the dynamicism of this, right? So I'm setting the image source at runtime, which is great. I can change a template as I need to before I stamp it out. And then the last line there is actually where the magic happens. So I'll get that content, I'll clone its node with all its attributes, and that's what makes that stuff go live. So at that point, this logo PNG would be pulled down, if I had stylesheets in the template, they be pulled down, media would be playing if it had autoplay. So clone, stamp out, and then stuff goes live. Another example. So this is actually really great, because it shows the inertness of script. So if I refresh this slide deck 1,000 times, it's never going to run this alert-- OK, thanks, bye-- until I actually stamp the template out. So we'll do the exact same thing. This time, I'm going to basically just going to increment this value. Every time I stamp it out, an instance is going to be created. And then the script will run as well. So when I press this run button, hopefully that will happen. You'll see, OK, thanks, bye. That script is immediately invoked when I stamp the template out. And I'm showing how to increment that value. So I'm changing the guts of the template on the fly. So HTML templates are a relatively new spec, actually, but support is actually coming along really nicely. So Firefox already has this, Chrome has this now, I'm including Opera Beta Mobile on this, because they recently moved to Chromium. So very cool. Proper at the DOM level HTML templates. Inert templates. So that's the first building block. Quick introduction. Let's move on to Shadow DOM. So Shadow DOM is an absolute complex beast. That's not Shadow DOM. This is also not Shadow DOM. This is a cool car that has the license plate SHDWDOM. But what Shadow DOM really is-- it gives us markup encapsulation, it gives us DOM encapsulation, it gives us CSS style boundary protection. So if you're writing a custom widget, if you're writing a component, you want your widget to look in a certain way. You've maybe designed it to be that way. You don't want things bleeding in or things bleeding out. So it gives us style boundaries. And what it really does is it exposes to us web developers the same mechanics browser vendors have been using to implement their own HTML elements. And so I mean by that-- you might also say, well, hey, Eric, the web already has encapsulation. It's the iframe, right? The iframe is great. We can import third party content into our page. But I would actually argue it's super bloated. For this use case, it's super bloated. It creates a new document context, scripting into it is very hard, you have to do crazy postMessage hacks. If you want an iframe to shrink wrap to your content, you have to figure that stuff out in JavaScript, and it's just a mess. And for the use case of component on a page, it's super bloated. But actually, what we have is something lurking in the shadows, no pun intended. And so there's a couple truths here that I want to highlight to you right now, and that's that DOM nodes today can already hidden DOM, and that the hidden DOM that they host cannot actually be traversed into from our scripts. We can't actually navigate into those or document course lecture into them. There's a couple of pretty good examples actually implemented in the web platform today, and those are some of the more complex input types. So input type date, or input type time are really great examples. With my keyboard, I can navigate these, I can increment these, so there's clearly something going on under the hood here. It's pretty interesting. I have a little increment widget, and there's this boom-- there's this calendar picker under the hood. All I do as a user is declare this input type date on my page, and I get all this extra goodness for free. So if I actually drill into this-- I'm an interested developer. I want to drill into the dev tools. You can turn on the dev tools under the wrench here, or the gear, show Shadow Dom. And so this is something you turn on. And then immediately when I do that, anything that has a Shadow Dom in the web platform, I can drill down into that's going to have this little triangle. Hopefully you guys can see that here. And so the input-- there's a hidden document [INAUDIBLE]. There's a hidden Shadow DOM attached to this input tag. And you can see what's happening is that the browser vendors have implemented this tag, the guts of it, the internals, using nothing but markup. So they've used what we as web developers have in our toolbelt-- markup-- they've implemented that with their native widget, not using C++ but markup. I think it's pretty cool. But from a user perspective, all I have to do on this page is just declare this element. And there's other examples. Video tag has all these buttons and stuff and sliders. Really cool. Textarea has a Shadow DOM. Details has a Shadow DOM. So all in all, the browser vendors have been holding out on us. Shame on them. But now they're exposing this to us. They're exposing the ability to create Shadow DOM. And so here's a quick example of how to actually create this Shadow DOM. I have my markup on the left here-- my host element that I'm attaching this hidden markup to. And what I do is I just call a query selector for that element, and I call createShadowRoot. So this is vendor prefixed, FYI. So createShadowRoot, and in that shadow root's inner HTML, I'm just going to fill in some markup. I'm going to put in an H2 that says, yo, y ou got replaced. And I'm going to put in by my awesome content just a div. And you can see what actually renders, right, in that, once I've attached that Shadow DOM, is the Shadow DOM content. It's not this stuff up here-- and we'll talk about that in a bit. It's the Shadow DOM. The Shadow DOM rules all. And here's an alternative view. This is what you would see in the dev tools, for instance. You see that hidden document fragment representing the Shadow DOM. So one thing that's really important if we're creating a custom element is you want some style protections. You want to be able to style things. Things that aren't styled are kind of unsexy on the web. So we have, with Shadow DOM, the ability of style encapsulation for free. This is one of the great properties of it. So in this instance, I'm using the same sort of inner HTML that I was before, the H2 and the div that says yo, you got replaced. But this time, I'm including a style tag that's going to color all of my internal H2s red, which is exactly why you see at the bottom that yo you got replaced is now red. But this is really cool, because I have an H2 at the top of the slide deck, right? The slide title's an H2. And that's not being styled red, because again, style encapsulation inside of my Shadow DOM, inside of my shadow root. Very cool. But we also have the ability to control this. So if you're creating, again, a component, and you want to embed this thing on your page, maybe you have a certain look and feel that you want to preserve. You don't want that thing to look completely out of place on your page. You want it to be seamlessly integrated. So we have a couple properties we can set. We have reset style inheritance, and we have apply author styles. Apply author styles is great. If I turn that on, set that to true, you can immediately see that my Shadow DOM content is now taking on the look and feel of this slide deck. Font faces are the same, line heights are same. Reset style inheritance just says, at that Shadow DOM boundary-- so there's this magical boundary that when your content turns rendering-- at that place, [INAUDIBLE] define Shadow DOM, any CSS properties that are inheritable, just resets those. So that's kind of a clean slate. That's how I can define my own styles, and not have inheritable properties bleed through into my Shadow DOM and my custom element. All right. Something else you probably want to do if you're creating a custom element is actually provide some default stylings for it. So say I want my element to be displayed block by default, or have a transition effect when somebody hovers over it. This is how I can do that from internal to my Shadow DOM. So there's a new @host at-rule that you can define. So this style tag would be inside of my Shadow DOM, and I define inside of it. I don't care what tag it is. You could be gangnam-style tag, you could be photo [INAUDIBLE] tag, you could be the x-blink tag. Whatever you are, set yourself to be opacity 0.2 and transition with an opacity to 1 when somebody hovers over you. So styling the host element or the component you're styling-- this is how you actually provide some default styles for that. You can set widths, whatever you want to do, right? So if you remember in the previous example, when I created that Shadow DOM, everything inside of that thing that I was attaching myself to completely went away, and what was rendered was the Shadow DOM. So you're probably saying, hey, what's up with that? And that's where insertion points come in. So insertion points are super powerful, because they allow you to sort of define-- I think of it as a declarative API, but that's probably not the best description for it. But what I have here is the same markup on my left. That's my host. That's the thing I'm going to attach the Shadow DOM to. My Shadow DOM is on the right, so I'm trying to style all H2s red. And what I have here is a couple of insertion points. And so this is a way, internal to your Shadow DOM, to define a structure similar to that input type date, right? It has this crazy internal structure. I can define placeholders for content from the left side, nodes from my host node, to then be funneled and distributed inside of my insertion points inside of my Shadow DOM. So internal structure in my Shadow DOM, and then the user can sort of put these nodes where they want, and I'm defining that internal structure. So content tag is your insertion point. And basically you use CSS selectors to select out nodes from the host and be funneled into the Shadow DOM. So this first example here is I'm selecting out all the H2s in my host node, and so that's why you see the my subtitle in the live demo at bottom. That's why that's rendered first, rather than this title that I've defined in the original host. The second one selects out all elements that have the class title, so that's why you're seeing my title, the H1 follow that my subtitle when this thing's actually rendered in the browser. I have some other markup inside of my Shadow DOM, and the last one, right, just says, hey, select everything else that wasn't selected out previously in insertion points. And so everything else in here that I haven't selected out previously, which is why an amazing description comes along for the ride at the end there. Insertion points are crazy. It kind of boggled my mind when I first started learning about them. So I actually created a tool to help myself and to help everybody that wants to learn about this. This is a pretty cool visualizer tool. Everything in blue is your host node. These are nodes that are coming from that host that you're attaching Shadow DOM to. Yellow is Shadow DOM content, so these are nodes and elements defining Shadow DOM. So you can see what I do is I have this sort of visualizer here. You've got your host node, and immediately, what the rendered compose tree looks like is the Shadow DOM is winning, right? So the first thing it's rendering is the Shadow Dom, and as I hover over these, you can see where they're coming from in the different sections. In this header, for instance, I have an insertion point. It's selecting out those H2s. One thing nice about this is that I can edit this on the fly. If I try to change this insertion point to select out H1s, it essentially becomes a no op in that case, right? There's nothing that it's selecting out, because I don't have any H1s in my host that are moving over to the Shadow DOM world. And I can also do the same thing up here. So if I add a bunch more H2s, it doesn't matter where they are, right? That insertion point is still going to select. That one that's selecting the H2s is still going to select those out and funnel those into the correct location internal to my widget Shadow DOM. Very cool. Very powerful, when you think about complex widgets, and we'll see some examples later on. Shadow DOM available in Chrome, and a couple of the mobile browsers. But I just want to point out there's a great session later on actually right in this room. There's polyfills for all the stuff. So you can actually play with this stuff today, which is really exciting. Shadow DOM is super complex, but having this encapsulated world is very, very powerful. Templates. Shadow DOM. Let's talk about custom elements. Anybody feel like this yet? I feel like this every day. Custom elements. Custom elements is sort of where all this comes together. It gives you with the element tag the ability to define new HTML elements. So basically, if I want to create the x-foo tag, I create this element definition with a name property, and the name is the custom element name that I'm creating. And so the only caveat here as you see on the little hover here is that the name has to have a hyphen in it. So it's got to have this dash in it. Similar to regular DOM elements-- the audio tag is a great example. I can create an audio tag using the new operator in JavaScript. I can define a constructor on my element as well, so people can then use that constructor or use the new operator to construct my element using new x-foo. So that's really cool. There's nothing different here. We're just defining a new element, and you should be able to do all the things that you can normally do. So until I actually have this definition, the browser sees this, it registers this element, it knows about it. x-foo, if I try to use that, it's just to be the HTML element. It's not going to be anything special. But what you can do-- there's a new CSS pseudo class, the unresolved pseudo class, that you can use to prevent things like flash of unstyled content. So if I want to, before the browser knows about-- so I have a bunch x-foos on my page, and I'm importing those later, maybe, I can choose to style any unresolved element-- I can set it to opacity is 0, so it's kind of hidden from the user. And then when the browser knows about it, the x-foo tag exists, transition that opacity in. So that's kind of a cool pro tip user experience there. You get life cycle callbacks for everything. So there's a ready callback that's called. There's an inserted callback that's called, and a remove callback. And the use case here is maybe you have a really complex component that uses something like index DB, right? And you have a lot of cleanup that you need to do before somebody rips and removes that DOM node from their page. And so you want to have things clean up. So in your remove callback, you would make those calls. And so there's sort of a life cycle of events and callbacks for everything. You really have insight into what's going on with your element. Here's an example of creating a definition. Just a pretty simple, standard, cookie cutter element definition. So I can put markup in here, I can put script, I have a section tag here. In my registration flow, in my restoration process for this element, here is that ready callback. So when this element has been registered in a browser, all I'm doing is just setting its inner text content to this section's text content. So it's pretty silly, but if I right click on this guy, this demo at the bottom here, and you see this, just to prove to you, hopefully you see the x-foo down there. And all it is, is just set to that inner text. It's a pretty silly custom element, but it's just to show you how simple it is. And similarly to native elements in the web platform, you can create a JavaScript API. You can create an imperative API on your element. So in this case, if somebody called x-foo-- the x-foo tag, they had that element that's created in JavaScript and called dash.foo, they would get an alert. So I can define a declarative element, but also an imperative API for it. So how do we use this thing once we define this awesome thing that's going to change the world? And the answer is, it's no different than normal elements. So I can declare it. I can use x-foo once that element definition is seen by the browser. I can create it in DOM, right? I can create using documentCreateElement with my x-foo. That's the tag I'm creating. And this example just shows you, you can set up a click listener, right? And then when somebody clicks on your element, you just call that method you've defined in your definition. So we'll call that foo method when the user clicks it. The last way, if we have that constructor attribute defined on our element definition, people can use and create our elements with the new operator. So three standard ways you use an element in HTML-- no different than the custom element world. If you want, you can go completely in JavaScript. If you want to register an element, create it in JavaScript, you can do that using document.register. So in this example, same element as I had before-- so just a quick glance, right? The section tag, the ready callback, the foo method. Same thing just in the JavaScript version. So I can use object.create, and I'm saying, OK, create an element for me. We're going to be inheriting from the HTML prototype. So basically just a standard element. I'll set up that ready callback in JavaScript on the prototype chain. And again, the ready callback, in this case, all it does is set the inner text to I'm an x-foo. Example of creating the imperative API. So I'll add that foo function to my prototype chain, which just alerts itself. And the last thing here-- to actually get this thing registered in the browser, call document.register, vendor prefixed, with the first argument is your tag name that you want to register, and the second is an object describing that prototype you just set up. And so once you do that, this thing returns a constructor that you can then use as you would normally expect. New x-foo, document.create, x-foo tag. Totally standard stuff. How about extending existing elements? You saw in the button is mega-button demo, right, I didn't like the way a button acted, so I wanted to extend it. And so the way you do that in your element definition is with one property here. Just extends="button". So I create a definition for mega-button, and I say extends="button". That's all you're doing. If you want, there's the JavaScript version. Same example, but in the JavaScript world. So this time, I'll use object.create, and instead of inheriting from HTML element, I'm inheriting from a specialized version of that. So I'm inheriting from HTML button elements prototype. And then you register it using document.register, give it the tag name, and that prototype you've set up. These are called type extension custom elements, so the button is a syntax. And there's actually a new overloaded version of create element-- document.createElement-- and the first argument you give it is the thing you want to create, and so the button. And the second argument is the is portion of that. So the button is mega-button, and what you get back, that would be the markup that's created for that. So that's a type extension custom element. So creating new ones, extending existing ones. What about template and Shadow DOM? I talked about that stuff earlier. It seems really cool. It's hard to understand. Where does all fit into this picture? And that is really that custom elements and Shadow DOM really are BFFs. And so here's an example of using that stuff I talked about before. If I want to encapsulate my markup and hide it in Shadow DOM so people can't traverse into it, I basically set up a template. So I'm using HTML templates inside of my custom element definition. You can see that I'm using the @host at-rule to style my element in a certain way. So in this case, I'm saying hey, please be display block at the bottom by default, and also have your background yellow. So I'm styling my x-foo-shadow tag to be these default styles. I have some markup in here. And in this case, since I have Shadow DOM, in my registration process, in my ready callback when the page has seen this element definition, I create Shadow DOM. So I don't just set inner text. I have to create this Shadow DOM from this template. This refers to the actual element itself. So that's my host node. I'm creating Shadow DOM and attaching it to my x-foo shadow tag. And I append the template contents. So I'll clone the content, right, just as you saw from earlier in the slides. I'll clone that, and that's going to be my Shadow DOM is the clone of this template. So the live demo at the bottom here, instead of having something that I can view from the outside world and traverse into, it's now encapsulated. It's not only style encapsulation, but markup encapsulation. So my x-foo down here, if I try to traverse into it, you see that document fragment now that's been attached. That's my Shadow DOM. That's the hidden markup, and inside of that is the stuff that I filled it with. So again, the only reason I can do this is because dev tools has that show Shadow DOM flag on. Normally, a person viewing source would only see this x-foo shadow tag. So it's really, really awesome. That's Shadow DOM, and that's how you use templates in Shadow DOM inside of a custom element. But what about insertion points? So I kind of glossed over that. I showed you the tool. This is where things get really, really powerful. I can define a my-tabs element, right? So this is going to be like a tabs widget. Inside of that, I'll create a template. Inert markup until I use it. And I'll create a couple of insertion points for people to adhere to. So this is my internal structure. I'm saying, please, markup, go here, go here, go here, and then I can style this inside of my custom element definition any way I want. So as a user of this tag, when somebody uses my-tabs, they would use it like this at the bottom, right? They would declare the my-tabs. Inside of it, they could put H2s, they could put section tags describing the tab, the title, and the content for it. And so internal to my custom element in my Shadow DOM, I make it look like this, right? With style encapsulation with my Shadow DOM. With insertion points, I can tell the H2s to go into these certain areas. So these become super, super powerful when you combine it with all these extra goodies. Firefox nightly has document.register, Chrome has document.register, and that's why these are partially highlighted. The actual definition part is not in any browser yet, but document.register is. You can play with it today. So templates, Shadow DOM, custom elements. The last piece of this equation is HTML imports. HTML imports allow us to import an entire HTML document inside of our application. All we have to do is declare a link rel-- so there's a new rel import type. So link rel="import", and then you reference an HTML file anywhere on the web, right? It can be on a CDN, it can be local to your app. Maybe this HTML file has a bunch of element definitions inside of it. So once I do that, that's where I get on my definitions from, and x-foo is defined in it. Then I can use that tag on my page. So this becomes really powerful, because then you can start to reuse other people's components, or you can reuse components you've written in the past. So inside of awesome-menu.html, I can link in an x-toolbar tag somebody's created. I can link in a menu item somebody's created. And when I'm creating this awesome menu, this new tag that I'm defining in HTML, I can use that work. So whether it's mine, somebody else's, totally cool. And so this is an example of a custom element using other custom elements. Kind of boggles your mind. But it's super, super handy, and really, really powerful. At the bottom, this is what somebody would use. My awesome menu. They would just instantiate the tag, and they would link rel import that. Very, very cool. This one is not supported anywhere yet. But it's polyfilled, so you can check out the session after this to learn more about it. So templates, right? Inert chunks of markup to be reused later. Shadow DOM for encapsulatable styles in DOM. Custom elements-- that will give us the actual definitions of how we create a new element in HTML. And HTML imports allow us to then import, whether it's a document, whether it's element definitions, any HTML into our own document. So hopefully you guys sort of see the zen moment here, which is pretty cool. It's very powerful. It's thinking about building apps in a declarative HTML way, which is different than we're currently thinking about it. A couple of inspiring demos, just for kicks. So we can create a meme gen tag, which is pretty cool. So this is a coworker, Seth Ladd, and he's on a beach right now. And I have content editable here. Sup Google IO. Web rocks! And so I've set a click listener for an on change event on this input, so this is internal to my widget and my component. I can change its background, so he can be now on the Golden Gate Bridge in San Francisco. Can throw him over an NYC if he needs to be. So again, and it's just a tag, right? So this is what somebody would declare on their page. They would give it a source, I've defined it an attribute on my element, just as with normal HTML. And then inside of it, they have H1s and H2s for those headers, and so those are insertion points, then, being funneled in to my custom element. But it's also about thinking about apps, right? So you can kind of encapsulate and encompass whole functionality into a tag now. So I can create a photo booth tag, and its sole purpose is to basically just wrap the get user media APIs to do a photo booth effect in the browser. We're going to get this to work, you guys. OK, we're not going to get it to work. But you can imagine my face going through this, and there's CSS filters and stuff. But very cool. So using other parts of the web platform, like new parts, like web RTC, wrap it in a tag, right? So now I have basically an app within an app, and all somebody has to do is link, import this into your app, and you've got that functionality for free. So can you try this today? The answer is totally you can try this today. Apart from that last demo, everything worked as expected. You can enable a couple feature flags in Chrome Canary. I definitely recommend Chrome Canary. It's got the experimental web features flag that you can enable, experimental JavaScript features flag. If you're trying Shadow DOM, trying to understand that crazy complex, please show Shadow DOM in the dev tools, enable that. Super, super handy. If you want to follow at least Chrome and Blink's implementation of the web component stuff, there's this hot list that you can link to. I'll have a link to the slides at the end, so don't take it down. But sort of in flight, low level stuff. If you want to know about where this stuff is in flight, check out the session right after this. It's about all these polyfill libraries that I've showed you. All the live demos. That's what the stuff is using. So plug for that. You don't even have to move in this room. This session's going to be up at webcomponentsshift.com. Again, I'm going to put in on GitHub, so there's my GitHub link down there. I really appreciate you guys' time. Thanks for tuning in on the live stream. Thank you.
- from
- Must Watch Talks, Web Components
- added
- 2026-10-10
- likes
- 0
Must Watch Talks › 2013: “[32:39]”