 Good morning, everybody. Thank you for coming. Thank you for coming to this 9 AM session for the jet lag and insomniacs, and those of you who haven't left from the party last night. So let's talk about web components. We had a whole bunch of titles for this talk. It doesn't actually match what's in the program. My favorite was the Miao Nika School for Kids who went to web component good and do other things good too. It was rejected. And Adios Wani suggested Miao Miao Pro Tips Miao Miao, which is pretty much what's going to happen here. So Miao Miao. Hi, everyone. I'm Monica. I'm not a world-run Twitter and GitHub and internet places. And officially at Google, I'm an Emojineer. And that's because I get very excited about Emoji, and I shout about it into the void that is Twitter. But what they actually pay me for it is to, oh, Emoji. So fun thing about this slide, I had to use Android Emoji and not the Apple ones. It was mandated by legal. And what I do is web components. And for the four people in the audience, I think, because we did a raise of hands. We don't know what that is. Web components are a standard we've been working on so that you can write reusable widgets for the web. So you can make your own fancy button and give it to people, and everybody can use it. I work on Polymer, which is a library that helps you write these web components. And in particular, I write web components with Polymer. We have elements like these ones that are like material design for me elements. We also have elements that don't look like anything. We have a declarative Ajax element that you can put in your page and get super easy XHR requests. And that's kind of fun. So you might not think of yourself as an element developer. You might think you're a web developer. You make apps. But if you want to start playing with web components, I think thinking like an element developer is really important. So you might only make elements for your own application, but you're kind of making them for future you, because future you's going to have to use these elements. And if they're crappy, future you's going to have a hard time. So I'm going to tell you basically all the mistakes I've made in the last year of making web components so that maybe you won't have to do the same ones. So there's like four things that I thought are kind of interesting about making web components. You've got to make an API that doesn't enrage your users. And this is actually kind of interesting. You've got to maintain this element once you start giving it out to people. You've got to make sure that it's fast and isn't like slow like molasses and destroys everybody's application. And you want to make sure that it's accessible. So these are the four things we're going to talk about. So let me tell you a story. In the 90s, we had HTML1. And it was lovely. And it was basically like reading the paper on the internet. Things that you might see on a page were things like links and headers and images if you were lucky. And that's all that happened. You opened a web page and you read it, and that was pretty much it. And in 1995, things got exciting. We got HTML2. And in HTML2, we got three awesome elements. We got input, we got form, and we got select. And I think we got button. Well, input type equals button was there. So now this meant that websites could offer you interaction. You can type something in a text box, and the website would react to you in some way. And the reason why I think this is important is that these are basically like OG web components. They're little reusable widgets that the platform gives you and you can put in your application. That's exactly what a web component is. And since 95, in the 21 years that we've had this, we've come up with a couple of more web components or whatever you want to call them. We have video and audio, which are kind of awesome. Canvas is like an enormous framework in and of itself. Dialogue and details and things like that aren't really implemented in all the browsers. And a lot of the input types aren't implemented in all the browsers. So the reason why I'm telling you is that even though we kind of had web components for something like 21 years, we're not very good at making web components. And I'm going to spend the next 10 minutes telling you how input is really terrible because that's one of my favorite things to do in life. On the other side of the world, we have Unix. And here's where it begins to be a little bit of a flame war. So we've had Unix since the 1970s. And one of the things that Unix is really good at is making reusable little programs that everybody knows how to use. These are the ones that I just used probably in the last week. These are the ones you've probably used ever in your life. Maybe not telnet and links, unless you're playing a joke on somebody. But Unix is really good at this. You use LS every day. Like if you use a terminal, you use LS every day. And the reason why Unix is so good at it is because Unix has a philosophy about how to write these super tiny components, commands, programs, whatever you want to call them. And that's what we're going to talk about for a little bit. Because if you're going to go ahead and write web components, I want you to think of what grep does and not what input does. Grep is a great example of a reusable component. Input is absolutely terrible. First thing. So yeah, Unix has like 17 bullets in their philosophy. And some of them are super meta, like value developers timed over computers, which is great. And I don't know what that means. But one of the ones that's the most popular one is that your component should do one thing. And this is 100% true of web components. If you build a component, it should be really tiny. It should do the thing that it says it does and it shouldn't do anything else. If you look at the cat command, cat takes a file from your computer and spits it out to the terminal. It doesn't try to print it. That's what LPR is there for. It doesn't try to find a string in it. That's what grep is there for. It doesn't try to sort it alphabetically. That's what sort is there for. Cat takes a file and prints it to the terminal. Input, on the other hand, has something like 21 types I think today, last time I checked. Even when it started in 1995, it had eight types, off the bat, that's how we started the races. And that's really terrible because they don't really have anything in common, these input types, other than they allow you to select a value. You have input type equals text, where you just like mash keyboards and they appear on screen. You have the slider, which like you drag a ball on a vertical slider and that magically picks a number. You have a color picker that gives you an RGB color. You have the map type, which is basically like an image map and where you click on that image is the thing that gets saved as a value. So again, all of these things, they have in common the fact that they have a value. They shouldn't be the same element. They don't even look the same. And then you start like painting yourself into a corner, once this is your API that you start with. So here, I'm creating input. It's a by default of type equals text. So it's an HTML input and because you can type in and it has a carrot, you can get where that carrot is and selection start is the property that you do this. And then I'm gonna change the type to input type equals number. I can still type, I still have a carrot. But now if I actually try to access that property, I get an exception. It's not that it's like a bad value. I literally get an exception. The browser panics. And this makes no sense from an API perspective. Both of these are an HTML input element. Both of these have the same prototype. They have the same property. And yet, if you access it on some types, like most of the types to be honest, the selection start just barfs on your console. And the reason why this is happening is because input type equals text and input type equals number should never have been the same element. They were the same element because in 1995, we didn't have JavaScript. We didn't have polyfills. We didn't know how to fall back to a default behavior. So we were just like, we're gonna put everything in one element and it's gonna have a default value and it's gonna be great. But 21 years later, we're still paying for these mistakes that we had to do in 1995 because of what the platform was like. So this is why don't look at input for API advice because input makes mistakes all the time. Another one of the Unix philosophies is composition. Programs play very nicely with other programs. In Unix, this happens with pipes. The output of any program can become the input of any program and everything works magically and beautifully. And the way this works on the web is by sort of nesting elements together. So select is composable, like select and option are composable. That's how you put elements in a checkbox. And you can put in text and you can put in a button and you can put in an input and an image. And what do you think is gonna happen here? Does anybody know what actually happens? Yeah, this happens. It's amazing. So the input gets rendered outside of the select box. We're not even trying. There's no image. And with a button, we're just taking its text value. This is not a composable element. This looks like it could be composable and select had a chance to get it really right. And they made a mess of it. And the historical reasons here are again because in 1995 when it came out, I4 on Windows didn't know how to draw select combo boxes otherwise. But 21 years later, again, we can do better. And with Polymer, we did do better. We made our own select box. We called it paper because it's material design. And in the dropdown, you can put on items. So you can put in text and you can put in an input and you can put in a button. And it looks like exactly what you would expect. There is the text, there is the button, there is the lemon. I don't know why you would put an input in a pop-up menu, but I mean, you could. Nobody's stopping you if you wanted to do that. And that's a composable element. So when you're making your elements, think about this. Are you expecting to have children composed in there? And if you do, try not to make assumptions about them. Try to expect sort of any types in there because people are gonna put inputs in your dropdown menus and you're gonna have to deal with it. And this one that leads me to extensibility, which is the code that you're writing today should work in 10 years from now unless it was written 40 years ago on a platform that is nothing like the Mac that I'm running it now. And unless it still works. It probably had to be recompiled, but I don't think anybody changed the source code dramatically. 20 years ago, we wrote form. And form is the opposite of an extensible end plan for the future element because form only works with the input element. And when I say it only works with the input, I mean, it is literally baked in the parser. When the parser gets to the form element, it only looks for elements that have the tag input and skips everything else. And this blows for us as web developers because what if I make a super awesome input now that is like way prettier than the crazy native input? I can't put it in a form because the form is gonna ignore it altogether. So I have to like start hacking around it and make hidden inputs so that the form recognizes it. So in contrast, in Polymer, we try to like not make assumptions about what sort of things, again, our element expects. We have the swipeable container where anything that you put in it gets this like magical Android swipe left or swipe right action. And this means that I can put in dibs and I can put in inputs and I can put in Polymer elements and I can even put in like web components that people wrote without Polymer. That element doesn't care, it accepts everything. And that's a really good element because if it works today, it's gonna work in the same way in like 10 years when the DOM might change a little bit but the platform stays, but the elements stay similar. So the point here is like to not make any assumptions when you're making your elements. And it's very, so the way I interpret it is that when you create your element, assume that it starts like sort of naked without anything. It doesn't have any property set on it. It doesn't have any children. It's just like born into the world. And then it starts reacting to things. When properties change, react to that. Don't assume that the properties are already set. If people add content to it, react to that. Assume that when your element starts up, it has nothing and you have to deal with everything that follows. And that means that pretty much in any way that people are gonna use your element, you're gonna be fine because you pretty much covered all your bases by just reacting to changes. And this also sort of leads me to this conversation about state because unlike Unix, and this is where Unix wins, Unix programs don't really have any state. They start up, you give them some input, they do something with the input and then they die and everybody's happy. But on the web, the input sort of lives there on the page for as long as that page is open and you're probably gonna type in it and it has to somehow remember what you typed in it and that's it is internal state, which isn't necessarily bad, but what you should do about it is that make sure that if your element changes its state internally, you communicate this to anybody who cares. You fire an event every time this internal state changes. And similarly, you as a user should be able to always change the internal state of this element in the same way that the element can do it. And guess what? Guess what input fails at? So input type equals number is kind of a good element because in theory, it lets you like validate what you type in it. So it lets you type in digits and a period for decimals and like the negative sign in E for exponents. So it doesn't let me type in monochrome emoji, which is great, I guess. So if I type in one, two, three, four, the internal value of the input is one, two, three, four. If I type in nothing, the value is nothing. And if I type in junk, the value is nothing, wait what? Yeah, so it turns out because this value is actually invalid, the input is going to secretly reset the value to the empty string, but not actually tell anyone. It's just gonna do it internally and not fire an event about it. And if you start with nothing and you type in junk, you as a programmer cannot detect this change. Like nobody has told you that anything has happened. But you with the eyeballs are looking at that input and be like, look, there's junk in it, you gotta do something about it. But as a programmer, you can because input is like hiding it's state away from you. So don't do that, don't be input. Which is pretty much the point of the stock, never be input. Because nobody really likes surprises. Like surprises in an API are the worst. Like finding that your cake is made out of kale and not cake and this is San Francisco where everything is made out of kale, this is the new tragedy in my life. So remember how I said that the reason why we painted ourselves into a corner with input is because in 1995 we didn't have polyfills. We had to somehow have a default type on all these stupid inputs and the only way we could do it is just jamming them into one object. But now we have polyfills, so we need to deal with polyfills. And the really important thing about polyfills is that if your element expects a polyfill, please for the love of God do not include that polyfill with the element. And here's the story. So we have an element that uses the web animation polyfill with the web animation spec which works on some browsers and on all of them. So there's polyfills for this and we were like, we're gonna be so nice to our users and include the polyfill with this element and everything's gonna be grand. You're gonna have a great time. And then Chrome settings came around and they're like, we would really like to use this element on Chrome settings, a page that runs on Chrome and no other browsers. Chrome has the web animation standard implemented. But because we jammed the polyfill in that element, Chrome has to actually download the polyfill for something they already know how to do on every single page. And that's really great, so they don't really wanna use that element and they hate us for it. So the moment you include the polyfill in your element, you take that choice away from the application developer. Maybe they wanna use a different polyfill. Maybe they don't even care about supporting an Internet Explorer, who cares? Don't jam the polyfill in there, you're not actually helping anyone. Document it, that it's required, but let the user take care of that. So what I hope you got from these last 10 minutes is that input is terrible and you should not look at it for any API advice. And that GRIP is kind of really good because Unix is actually really good at making this. So if you wanna read the 17 bullets of Unix philosophy, I strongly recommend it. They're kind of really interesting and they're probably gonna make you make better APIs. Help you make better APIs, got it in the end. Awesome, so we have an element. We've given it to people, it has a beautiful API, nobody hates us for it, and now we actually have to maintain it somehow. So the thing about maintaining your elements and why it's important is that if you go on NPM and you download a package that hasn't been updated in two years, this is gonna give you the creepy GBs. Like if nobody cares about this package and nobody's fixing it, then I'm probably gonna be running with a lot of bugs. This is the same with web components. If you want people to use your elements, you gotta keep your elements up to date because that makes them cool and usable. And one way we in Polymer do this is by making sure that we follow Semver. Whoa, whoa, whoa, whoa, whoa, whoa. That was exciting. We got there, Semver. I get excited with Semver all the time. So Semver stands for semantic versioning and it basically means that every one of these numbers in these versions actually means something. They're not just random. So the last number, on the right here, I have a tweet from Dave Method who makes fun of Semver because no matter what you think you're shipping, you're actually gonna break your users. So, you know, keep that in mind. The last number means that this patch has a patch fix. It has bug fixes, it's still backwards compatible, everything is A-OK. The middle one means that you're shipping some features but they're still backwards compatible. So if you're using this version yesterday and then you update and then you get the new version, your app should still be fine. You're gonna get new features, you don't have to use them but like everything that used to work should still continue to work. It probably won't because you'll write some bugs but that's a different problem. And the first one is a major version. This means you're actually introducing breaking changes. So if somebody wants to pick up this new version, they actually have to do a little bit of work for everything to work in their application. And there's two things I wanna tell you about major version bumps. One of them, numbers don't have meanings. Please do not think that increasing your major version is actually like a marketing ploy or anything like that. Don't get obsessed about this. All you're doing is communicating that this version has breaking changes, you're gonna have a bit of a hard time. And the second one is just because you can communicate this breaking changes doesn't mean you should have really aggressive breaking changes. Breaking changes are really terrible for your users. They have to do work, they have to read the new API and figure out how you broke them and figure out how to make their stuff work again. So in Polymer we try to be very deliberate. We haven't shipped a major change yet because we wanna make sure that the moment we ship it it's a right change and it's gonna not be actually very hard for users to update to it. So be very deliberate about what you're shipping and make a major change. Don't just abuse it because you can't communicate it. That's what Ruby does. So now that we have Sember, we can tell the users that this version is gonna break you or not. But the only way we're gonna figure out if we're actually gonna break users is by testing. And this should not be new to anyone. You write software, you test it, duh. But testing Web Components is kind of interesting because Web Components are new and I found that I had to test things that I did not expect that I had to test. The first one is obviously the public API. If you pinky swear that a function exists, you should make sure that function exists and does what it says it should do, duh. And I'm trying to click now. We're having great times with this remote. I really like it. So the other thing is that you might wanna start introducing this idea of like a private API. JavaScript doesn't care, so don't worry about that one. But if you introduce a convention like underscore means private, you get to be responsible for less of that API. Like a lot of your configuration methods or any of your internal functions, you don't have to make them public because if you make them public, you're responsible for them. But if you make them private, then anybody who's using them, you can be like, listen, you're on your own. I told you not to use it. If you really wanna use it, I can't promise it's gonna be there. So in Polymer, you use underscores, any functions or properties that serve with an underscore or two underscores if it's a behavior. Are private, use them at your own cost. I might just delete them for shits and giggles. You should test your accessibility. So elements should be accessible and I'm gonna like rail on this one in about 20 minutes. But you should also test this. You should unit test it because you don't wanna break it. We use the accessibility developer tools. It's on GitHub under Google Chrome. That's what this cryptic diagram means. And they're basically an API that you can run as a unit test. And every time you set something like roll on an element, it like runs 20 tests and make sure all the ARIA labels are set up correctly and tab indexes are set up correctly and your contrast isn't terrible. So that's really good. You can automate them. You should also test the look and feel and this is where things get interested. Because you're vending elements that look like something, the thing that they look like kind of becomes part of your contract with the API, with the element user. So I discovered this a super hard way where we had an element, it was a button and I thought I was being extremely awesome and I changed the box sizing from content box to border box and I was like everybody's gonna love this change and I broke like 15 people because it turns out if you change it to border box and somebody was sending a size on that element, that side is now completely messed up and they're gonna have to adjust everything and add 20 pixels to everything. And I shipped that as a bug fix and it was actually breaking change, go me. And that's because I didn't have any tests for the UI. So make sure you actually test the UI because you're promising your user that a thing looks like the thing it should look like. Here's a bunch of UI frameworks and libraries that let you make UI tests. I don't care which one you use, just use one. You don't even have to use, everybody's taking pictures of these, nice. You don't even have to use this one. You can literally do like get bounding client direct on your elements and make sure they're the right size and like the font size is the same. Do whatever you want as long as you test your shit. And finally remember I told you elements are composable and they like should accept children and they should like work in other things. So if your element should be composable and that's the thing that you care about, make sure that you test it. If you're writing something that's like a form, put all sorts of things in that form and make sure it doesn't crash. If you think it's like an input, put it inside a form and see that works fine. Test your things. Cool, we're testing. We have Semver. We're telling the users we're updating our elements. Users trust us, they're delighted with our elements, they're gonna use them forever. We need to actually write documentation about it because if you don't WTFM, you can't tell people to RTFM later. So cover your bases now. If your element has any edge cases, document them. I don't care that your element is being weird if it's in like RTL mode as long as you tell me about it. Because otherwise I'm gonna write this like super lonely Stack Overflow post that nobody's gonna respond to and I'm just gonna be sitting there and be like, it's been 10 hours, why doesn't this element work? Just document your shit, it's gonna be great. We're maintaining our element, everything's great. Let's talk about performance. So performance has been a big topic at IO. Performant apps, we want fast apps, fast apps lead to user engagement, lead to more views, leads to me getting promoted and getting paid more, everybody wants that. But when we talk about elements, performance is actually really important because it doesn't matter how fast I make my application, I can use a rail and purple and everything. If I'm building it out of really terrible and slow elements, there's nothing that I can do. Which means that you as an element developer have to be very careful about what you put in an element because it's gonna screw somebody in a major way later. So if you think about your element, maybe it's like one millisecond fast, let's say it's a checkbox and it takes one millisecond to paint because that's what we really, oh, do one thing, do it fast, duh. So if you think about painting, if it takes one millisecond to paint your element, you might like high five yourself and be like, one millisecond is the fastest paint I've ever heard of in my life, I'm doing great. But if I have like a thousand pizza toppings on that page and they're all checkboxes, you've now added a whole second to that page. And a whole second to a webpage is actually enormous. We've been trying to like save milliseconds out of pages and you just made it so much slower. So focus on first paint and make sure that the first time your element shows up on the page is as fast as that can possibly be. Steve Orwell on the Polymer team has an amazing rule about this. The best advice about how to make your element be fast is do less and be lazy. This applies to like anything that you wanna be fast. Do less, be lazy. By do less, we literally mean that. Don't do anything you don't need before first paint. Don't like said magical handlers, don't said magical styles that are needed maybe later. So we had this code a lot in a lot of our Polymer elements where like when the element was being attached so when it was actually inserted in the DOM, we were updating the pointer events to make sure you couldn't click on disable things and we are adding click handlers. And this looks like very reasonable code, right? It's very short. It probably doesn't take very long to run. But again, if you do it a thousand times, that's a thousand event listeners you're setting up before you're painting the page. That's enormous. So what we do now is we wrap it in this like after next render. We do everything that's needed for paint. This isn't needed for first paint. And everything that's needed like literally the tick right after it painted, we do it after the next render. And this is really great because now my page paints really fast, my elements paint really fast and they're interactable, the milliseconds like instantly right after. So everything is perfect and everything is fast. Be lazy takes that one step, one step further. Don't do anything unless somebody actually asks you for it. And just like volunteer to do work. That's bonkers. You would never do that in real life. I have nothing to do right now. Let me do some work. It's great. You'll watch Netflix. You know you do. So in Polymer, we have a lot of Polymer elements. They implement the material design spec. And the material design spec has this thing where like every time you click on something, it has like a really satisfying ripple that is a little jiggle and everything's really nice and fun. So the way we're coding it up is that literally every element had a ripple element inside of it. Checkboxes, buttons, inputs, everything had a ripple. Which sounds really great in theory, right? Like it should ripple. We should put a ripple element in there. Turns out that's crazy. Let's go back to my pizza topping analogy. I have a thousand pizza toppings. I'm probably gonna click on like four of them because I've tried to put all the pizza toppings on a pizza before and it is terrible. Don't do it. Pineapple and mushrooms don't go together. They go together with onions though. So if you're only gonna like click on three things, you only need three ripples. You're now creating like 997 ripples you don't actually need. So we update our code and we do something else now where no element has a ripple when it starts up. But if you click on it, the first thing it's gonna do on that click end would be like, do I have a ripple? No, well here's a ripple, make a jiggle. So now in this enormous application, we're only creating the ripples we actually need. We're being incredibly lazy. And this makes everything super fast because I'm not just creating DOM nodes that are sitting on the page doing absolutely nothing. Not even giving them access to Netflix. Do less, be lazy. Do less, be lazy. This is your mantra, tattoo it somewhere. And we didn't just like come up with this one day. Well, Steve did, he woke up, he's listening to like this weird podcast I think that tells him that. But like we actually started writing tests for performance to figure out how this was going. And there's many different ways in which you can test performance and they're all terrifying because I'm actually terrified of everybody else's frameworks. So I have like two simple ones that I use and they work really well. The first one is console.time. So console.time takes a label and basically like between the first time you call time and time end on that label, it calculates how much time this costs. And you can also nest them so you can be like, well, creation took this long but setting attributes took this long. And the reason why console.time is nice is because you get a timeline in the dev tools and you can see like what's actually happening here. This is incredibly fast because I was just doing random numbers in a loop. You're never gonna get code that runs in 10 milliseconds like that. But yeah, so that's console.time. It gives you a timeline. If you're even lazier than that and you don't care about that, you can use performance.now which literally just tells you milliseconds now, milliseconds now. So you can do it before and you can do it after a task and see how long that took. And the thing that you do inside if you wanna test your first paint is that you wanna create your element, you wanna attach it to the body and you wanna do a giant hack. So let's talk about this giant hack. In the same way that we're optimizing our elements, the browser has been optimizing itself because it assumes that we're terrible developers which we are. So just because you're appending something to the body, it doesn't actually mean Chrome is gonna paint it. Chrome is gonna like wait to batch them. If that thing is invisible, Chrome doesn't even care. If it doesn't affect the layout, it doesn't care. And you can't actually tell Chrome to paint things. So the only way we can time this correctly is by sort of forcing Chrome to relay out the entire page which also forces it to paint. OffsidWidth is one of these attributes so when you call it on an element as a style attribute, it has to recalculate the layout because it's in reference to its parents. So that's the one that I use. Pretty much anything with the word offset in it is gonna cause a relay out. You can Google for all the other ones if you don't like it. But the idea here is that if you want to make sure your element has painted, somehow trigger a relay out on the page. And the follow up to that is don't do this once. Do it like a thousand times. Do it as many times as you have time for because if you only do it once, anything could have happened in there. Somebody could have sent you an animated gift to your Slack channel which slows down your computer. The garbage collector could have run. The garbage collector could have not run. If you do it a thousand times, you'll get more accurate numbers, you'll actually get a good answer about how slow or how fast your element is at painting. And the reason why this is awesome is that now you can automate it. You can put this in a unit test. You can put it in a test that you run on every merge. And then on every merge you can be like, well, this element was like 10 milliseconds fast yesterday and it's now 15. And then you can ask yourself whether the feature you're adding or the bug fix you're adding is actually worth this performance cost you're taking. So let's talk about accessibility. There's this amazing quote about, so anywho, the conclusion here just to like bring it home is test your elements for performance, make sure they are fast. If your elements are really slow, I hate you and you're gonna slow down the web. Please don't slow out the web. It's really hard for all of us. Accessibility. So there's this amazing quote by Cordelia Dillon which is that accessibility is like a blueberry muffin. So the way you make a blueberry muffin isn't by taking a plain muffin and a fistful of blueberries and jamming them in there and be like, I made you a blueberry muffin. You made me garbage. The way you make a blueberry muffin is by taking the eggs and the flour and the sugar and the butter and beating them together and adding the blueberries to the sardau and putting them in the oven and waiting for 35 minutes and then you get delicious blueberry muffins. Accessibility is hard. You have to do it the entire time from the birth of your element to the end of your element in the same way that you make muffins. You can't just make an element and the last day before you ship it, you're like, shit, I didn't make it accessible. Let me jam some Aria labels in there. You're going to make a terrible job about it. And the reason why this is important is that if you don't have accessible elements, you're not going to be able to make accessible apps. And if you don't want to make accessible apps, you're a terrible person and you shouldn't be making apps for anybody. You should be doing something else. Thanks, y'all. Rob Dodson gave a really good talk yesterday at 9 a.m. on this stage about how to make your elements accessible. And I strongly recommend going and watching it at home and it's an amazing talk. And he tells you proper concrete things on how to make it better. I'm going to tell you two things that I got wrong because they were really easy things for me to get right and I didn't. Focus states are a really big one. Focus states tell you where the focus is on the page. It's a really ugly outline that in the 2000s, it was really cool to set outline none on focus because nobody really liked it. And that's really terrible because if you're not using the mouse and you're just using the keyboard, you're not going to know where you're on the page. But even if you are a mouse user, if it's just like you, remember the last time you had to buy something on the internet and at the end you get to the 15 field visa credit form where you have to fill in on your information, your shipping address, your mailing address, your name and your credit card number, and you're going to be tabbing through them. I promise you, you don't actually click on every single field. I know you. And if nobody is telling you where the focus is on that page, you're going to start typing your credit card number in your address field. You're going to get frustrated. It's already a frustrating experience buying things on the internet. Don't make it worse. Don't make bad UIs for people. I don't care whether you use this outline or a different outline or you're communicating focus in a different way as long as you are communicating focus in some way. You can make like a nice ripple around it. Just make sure that if somebody is using the keyboard, they know where the focus is on that page. And the platform helps you with this. Tab index equals zero, whatever you put it on, that thing becomes focusable. And by default, at least it gets the really ugly outline. It's ugly, but you're doing better than not doing anything at all. And the other thing is that you have document.activeElement, which tells you where the focus is on that page, which means now you can unit test this and automate this. Make a test where you have 17 of your elements and simulate tabbing through it and check that the thing that is focused is the thing that you expect to be focused and it's styled like you expect it to be focused. Unit tests are the best. They make sure that your element doesn't randomly break. The platform also gives you ARIA. ARIA is what voiceover applications use to read HTML. There's a whole bunch of documentation ARIA. I'm not gonna talk about ARIA. I just wanna mention that some elements have built-in ARIA, like nav and a, have extra ARIA built in themselves. And that ARIA labeled by is this really awesome attribute that is basically ARIA label on steroids because if an element already has a built-in ARIA label, like the native input does, it uses the ARIA label to read whatever you typed in it, you can't put an extra ARIA label on it. You can only have one. So if you wanna make the native input more accessible, like say with a label that describes it what it's for, ARIA labeled by is there for that. It always adds more information to any element. So this is really important. Please make your elements accessible because if we're gonna make accessible elements, we're going to get accessible apps. And the same thing happens for performance. If you have fast elements, you're gonna get a fast app. And if you have maintainable elements, you're gonna get a maintainable app. And that's really our goal as element developers. We wanna make the web better. We wanna make amazing apps for other people. So that's it. I hope you got something out of the stock. Please go home and make elements. And if you do, tweet them at me so I can see what you made. Thanks.