 How are you all doing? Good? Yeah, yeah, all right, cool. So this talk is going to be about my journey to try to get the whole world using custom elements and some of the interesting things that I've learned along the way. So I've been at Google for maybe a little over three years at this point. And during pretty much that whole time, I've worked on custom elements and web components. And it's my belief that if you're building a UI library and you're working at like a mid to large size company, so you want to build a whole bunch of components and share it with a bunch of teams that are all on different stacks, that custom elements and web components are really like the way to go about doing that. And this story is basically what I've been advocating for all these years. And being the point person for custom elements and web components means I get a lot of feedback on that idea. And feedback that kind of looks like that, right? So this is a tweet from a fellow Googler who was trying to use web components with another framework. And he said, every few days I see someone like Rob say that web components work in all frameworks. All of our problems are solved. And it's really clear that no one has tried any of the above. And you will notice that this is tweet 6B of a very long list of grievances and subordinate sub-greavances that rolled up into the larger tweet storm. So very organized and very emblematic of a lot of the feedback that I've gotten over the years. And it kind of boils down to this. We say that custom elements should work everywhere, right? That they are based on web standards, that they are the future of the platform. So we say that, and then why don't they, right? And the more I thought about this, the more I started to wonder if perhaps we put the cart before the horse. And did we maybe get so caught up in the fact that we could build custom elements that we didn't stop and spend time to think about how we should build them in the first place? And if custom elements and the things that we build, if they are unpredictable or they are inconsistent, does that then make it harder for frameworks to work with them? And so that's really what I set out to find out. So I split this talk into two parts. The first is my journey just to identify what a quote unquote good custom element would look like. And then the second part is looking at how frameworks should work with those elements. And my hope is that by the end of this, you all will have a better understanding of how to author your components and also what to expect when you try to use those components with other frameworks or libraries. So let's dive into that first point. What is a good custom element? And to start this journey, I actually went to the Chrome engineer who was in charge of implementing custom elements APIs in the browser. And I said to him, I was like, hey, do you know if there are any reference custom elements that I could look at, stuff which you think really lives up to the standard? My thinking there was that the people that write the specs and the people that actually implement the APIs in Chrome, surely they've gone and built a bunch of custom elements. And they're like, these are our ideal components. And all components should live up to these. His response was a bit surprising because he was like, nope. None that I've seen. And that really got me thinking. I was like, hmm, all right. So we need to identify the best practices for custom elements. And I'm not really sure how to do that. But maybe what we could do is assemble like a crack team of engineers. And then together, we could probe the depths of the HTML spec and we'd uncover all the treasures that lay within. So that is exactly what we did. Working with my teammates, Serma, Monica, and Eva, we began writing a set of vanilla custom elements. So not using Polymer or anything like that. Just vanilla JavaScript custom elements. And we wanted to figure out how the heck these things should actually be authored. And along the way, we learned a lot. And in fact, we're still learning a lot. But what I wanted to do is go through some of the stuff that we've tried to capture so far. And we've been doing this work inside of an element set, which we call the how-to components. So the how-to components, these are a collection of educational custom elements. We're saying that this is sort of like literate code. So we want folks to actually look at the implementation, read them, look at the comments, and understand why we did the things that we did. Now I want to be really clear. These elements that I'm talking about here, these are not things that you should use in production. They're not even styled, really. These won't be going on webcomponents.org or anything like that. Instead, we wanted to create a resource where developers could read the source code kind of side by side with the comments and then learn from the elements and understand why we made certain decisions. And then take that knowledge and actually go apply it to the custom elements that they are building within their own company. I want to be also really clear that this is a work in progress project. Don't be surprised if you're looking at the repo. We start changing things around. Because basically, as we learn new ideas, and it happens all the time, we learn new ideas and we bring them to all the elements and we update them all at once. So again, it's not a production thing. It's not something you should actually use the code or anything. We just want you to read it, interpret it, and think about it. Because what we want to do is create a resource where we can all learn in the open and have discussions on GitHub about, OK, well, why should we do this? Why should we not do this? So if you want to check these out, you actually can. The repo is available up on GitHub. Here's a direct link to it. And I'd like to walk through some of the best practices we learned as we were doing this. So I split this up into three topics we're going to try and cover. How do you deal with Shadow DOM? How do you handle attributes and properties? And how do you manage events in your elements? And I want to be clear that what I'm going to talk about today are guidelines. So these are not meant to be rules or laws that you have to follow. Because the web platform is not really consistent all the time, not by a long shot. And so you should always feel free, when you're building your own element, to color outside of the lines if you need to. If your element calls for it, you get to make that decision. But having said that, I do want to dive into some of these best practices. And we'll start with Shadow DOM and some of the things that we learned. Now, the first question that comes to mind when you think about Shadow DOM and you're building a custom element, especially if you're doing it as a vanilla custom element and you're writing all the JavaScript yourself, you're not using a library or anything, is does my element even need Shadow DOM? And I have to admit, personally over the last maybe year and a half, I got a little cranky with Shadow DOM. I got a little frustrated with it at times. And I've got the team, the Polymer team, they're like, dude, you got to use Shadow DOM. You got to use Shadow DOM when you're building custom elements, you always got to use it. And I'm like, hey, you know what, Shadow DOM, it can be kind of annoying to work with at times. It can be hard to re-theme. The polyfill can be a little wonky. And you know what, maybe you just don't tell me what to do and I'll build my own elements, okay? And so yeah, deal with it, boom. And so that is actually how we started this process. We were like, we're just going to build vanilla custom elements, we're not going to use Shadow DOM, we're just going to do our own thing. So the first element we created was a checkbox. Here it is, very simple, how to checkbox, right? Seems straightforward enough, it's a single tag, it doesn't have any children. I didn't see why something like this would need Shadow DOM. So instead, we were like, okay, cool, we have a JavaScript file for our element definition and then we have a CSS file for all of the styles, okay? But very quickly, we discovered that if someone takes your element and you're using a global style sheet like that, so they take your element and they put it inside of another element that uses Shadow DOM, okay, well now all of your styles are broken because you don't have a way of getting your style sheet into that other element's scope. I mean, maybe they can like link out to your style sheet or you could have like a build tool or some build process like inject your styles into their element or something. But it basically means that like, it's up to you and that developer to figure out how you're gonna get your styles into their scope. So that was a little, I felt kind of not awesome about that, but whatever. And oh, I should point this out because this is actually really interesting. There is actually a discussion to see if we can streamline this a little bit. So there's a thread on the W3C GitHub where Steve Orville, a member of the Polymer team has proposed this notion of if you have a very simple custom element, like a single tag, something that doesn't have children or anything like that. Could we maybe, as you registered the element, also give it a style sheet object? And that would work almost like a user agent style sheet just for that tag. So this is a really cool proposal and something that I actually hope we land at some point. But today, this is not real, it's not shipping anywhere. And it made me realize that you probably need to create a shadow root if your element is gonna self-apply any styles. And you might have a shadow root that only contains a style tag, and that's totally okay. The benefit is that your element starts to become a lot easier for people to reuse. They can use it outside of Shadow DOM, they can use it inside of Shadow DOM, right, they can put it inside of more complex elements and it just works. Now as we were working through this first element, conversation kind of popped up on my Twitter feed. And someone said, I'm kind of paraphrasing the original tweet here, but someone said, you know, since we have things like CSS and JS for scoping our styles, do we actually still need Shadow DOM? I mean, can I just use these fancy build tools? And it was actually Trey Shigart who'll be speaking tomorrow who responded on Twitter and he said, you know, style scoping is a really cool benefit of Shadow DOM, but aside from style scoping, one of the other major benefits is DOM encapsulation. So if you're building an element when it creates its own children as part of its implementation, you can actually hide those children, you can hide that implementation inside of that little DOM scoping bubble. And this is really crucial for framework interoperability. And so he shared a example that I wanna walk you all through because I think it's really interesting. So let's say we're building an element and we're building a counter. So it's just gonna say the word count and then have like a number next to it, like count one, two, three and so on, right? So I've got a little div here in my template with the word count and then I'm gonna slot because I'm gonna assume that this framework or library that I'm using my element with that they're gonna put the number in there for me. I'm gonna create two versions of this element. So the first one is count with shadow. So here I'm creating a shadow root. I'm just appending my template content inside of the shadow root when my element is constructed. The other version that I'm gonna create is gonna be called count without shadow. So this time, instead of using Shadow DOM at all, we're just going to stamp that template content into the light DOM. I'm cheating a little bit because slot elements don't work outside of shadow roots, but whatever, go with it, go with it, pretend it does, right? So let's look at what happens when we try and use this inside of something like react. So in react, I've got my little render function here and I'm going to try and stamp out both of those elements and I'm just gonna have react pass in the count. So every tick is just gonna pass a number as a child of each of these elements, one, two, three and so on. So what do we get when this renders? Well, you might be a little surprised. The first element looks like we would expect it to, right? So you've got count one. The second element though looks totally broken and I wanted to dive into that a little bit. So why is that? So in this first implementation, all react can see inside of this element is just the number one, which you put inside of there. Now we know there's a shadow root and inside of that shadow root is the word count and our slot tag, but react isn't able to see any of that because it's not piercing shadow boundaries or anything and this is good. It means our implementation is hidden. If we look at this second element though, it's kind of more interesting because it seems like react created an element and then put some text inside of it and then attached it to the document and then our connected callback ran and all our stuff stamped out after the content. Okay, so already that looks broken. Probably not what we want, but it gets a little bit worse too. So the next tick, react is gonna look at this and it's gonna be like in my render function, you told me about the number, but you didn't tell me about this div thing here. Really, what is that? I don't know, you didn't tell me how to render any of that. So what's it gonna do? It's just gonna delete it. And so the next phase just throws away all the light DOM children and now we just have the number two inside of that element. Now I did some tests and I found that other frameworks may leave your light DOM children in place or they may not. There's really nothing to enforce that. It's just kind of a convention that they may or may not adopt. And so what we learned from this is if you're authoring an element that creates children, you probably wanna put those children inside of a shadow root. That's because those children are part of your implementation and the rest of the page should not need to know about them. So after all of this thinking, going back to the original question, does your element need shadow DOM? I think it actually probably does. And even though it can be a little frustrating and it can make you kind of cranky to work with it at times, shadow DOM is really important because without shadow DOM, you lose all guarantees of safety. You know, if you wanna put your element inside of another element or you wanna put your element inside of another framework where there's other JavaScript actors at play, shadow DOM kind of protects your implementation from the outside world. It's the little engine that makes the framework interoperability story go. Okay, so that takes care of shadow DOM, quick recap there. Definitely if you're self-applying stylist, you probably want a shadow root and any children that you create should go inside of your shadow root. Let's talk about attributes and properties. Basically, how does your element handle data and reflecting state to the outside world? This might seem like minutiae, this might seem like a very boring topic to talk about, but when it comes to framework interoperability bugs and issues, this area is actually where I found the most problems and the most differences across the board. And this is like a really contentious topic actually. So even the Chrome team and the people that work on specs and the people that work on Polymer have different ideas about how elements should handle attributes and properties. And I wanted to try and do my best to get to the bottom of this and just put out some semblance of best practices. So when we think about attributes and properties, like what would we consider canonical behavior? It's like, okay, well, I mean, where would I even look to figure that out? Well, there's HTML, right? HTML has a spec, and it actually, if you read the HTML spec, it explains how attributes and properties should work on elements. And so it's like, okay, cool, well, I guess we'll read the HTML spec and we'll just do everything it says. I don't know how many of y'all spend much time reading the HTML spec and really diving in there. It's actually pretty gnarly the deeper you go. If you dig down deep enough, you'll find inconsistencies, you'll find anachronisms, you'll find stuff that seems to kind of predate the current era of standardization, like older elements like input are just super weird. So it can make it kind of hard to distill out what one would consider like the best practices. But for all of its faults, it's also kind of the only model that we really have to follow. So if you can make a custom element that's mostly indistinguishable from the behavior that built-in native tags have, I think there's a really good chance that frameworks will be able to work well with your component. So here are some of the best practices that we came up with. The first is that for primitive data, so strings, numbers, booleans, you want to always accept that as either attributes or properties, ideally both. So someone should be able to just walk up to your element and call like set attribute for a particular thing or set a property, like a corresponding property, and both of those should just work. And ideally, you want to reflect back and forth between your attribute and your property. So let me give you an example of that from a native element. So if we look at the native video tag, I want you to see this behavior because it's actually pretty interesting. So this element has a preload property. It also has a preload attribute, right, the correspond. I can go up to this element and I can actually query it and I can say, all right, what is your preload property value? And I'll say by default it's auto. And I can set that property to none and you'll see it sprouts an attribute when I do that. And I can then read that property value again and it's actually reading it off of the attribute. And I was like, okay, cool, that's interesting. Can we mimic the behavior of built-in elements with our own elements? And so my understanding from talking to spec authors is that the way this behavior is implemented in native HTML is that there are getters and setters for all the properties and the getters and setters are actually like really dumb. The only thing they really do is just kind of reflect back and forth to attribute. So I'm gonna make like a fake element here called custom video and in my getter, I'm just going to try and get the value from the attribute. If there is one, I'll return it. If there's not, I will return a default value. So this is that default auto string that we saw. So this is kind of interesting because you're co-locating the default value with the property, with the getter and setter. In the setter, all we do is we take the value that was passed in and we reflect that to the attribute. And because the getter is leveraging the attribute, we have now synced our properties and attributes. So you change one, it changes the other. That's pretty interesting. We don't have to write any additional code. You don't have to have like a little underscored property that you're sort of like managing under the hood and all this private state. Instead, these two worlds are just in harmony now. So I thought that was really interesting. And so you can see this in action with this like custom video element that I created here. So you can go and you can look at it and basically the same behavior. So we can read the preload property, we get the default value out of that getter. We set it, we now sort of spring an attribute and then we read the property again. It's reading it off of that attribute. So for primitive data, I feel like this behavior actually works quite well. And it makes things very consistent. So someone can fiddle around with an element and still call get attribute on it and get the right data. There are exceptions to this rule. So you might not want to reflect properties that are like really high frequency. So for instance, the native video tag also has a current time property. And that is basically every millisecond it's updating the current time for the video. So reflecting something like that probably don't wanna do. Again, in the HTML spec, there's inconsistencies and quirks and there's reasons to color outside the lines. But generally speaking, primitive attributes and properties reflecting seems like a good thing. And it can simplify your mental model as well, right? It can help you understand how to write your component if you just do this consistently. So that's good for primitive data. What about rich data, like objects and arrays? So I think this is really interesting because I think for rich data, you probably only wanna accept that as properties on your element. And there's reasons for this. Oh, also you probably don't wanna reflect rich data from properties back to attributes. And the reason is because one, it's expensive to reflect, right? So stringifying a big object that someone passed in as a property and reflecting that, that just doesn't seem very useful. Polymer actually used to do this. Like Polymer is zero five, we reflected everything. And we stopped because people were sending these massive JSON objects down and then we would stringify it all and reflect it for very little gain. We're just spending a bunch of time parsing and unparsing JavaScript. The other reason I think you should avoid this though is because a serialized object loses all of its identity. So this is something that my teammate Justin pointed out and it's pretty interesting. So if you take an object and that object has references to other objects and then you call JSON stringify on that, well you've just broken all of those references, they don't work anymore. So you pass that to some element and maybe the person is expecting mutating that object to mutate some of the original sub-properties and that just doesn't work, right? So if you just stick to properties you kind of avoid all this weird string bizarroness. So definitely recommend that. All right, so for attributes and properties, quick recap, primitive data, you want it as either attribute or property. You ideally want both and you want them to reflect. And then for rich data, objects and arrays, I think you're an element should really just accept those as properties and that'll make your life a lot simpler. Last thing and I'm gonna be quick about this is events. When should an element dispatch events? Now this seems like, I don't know, kind of a weird question to ask but then when you really think about it, it's kind of interesting because if you look at native built-in elements, they do not seem to dispatch events in response to like a host setting property or anything like that. And I think there's a good reason for this. It's kind of superfluous, right? You set a property and suddenly your element dispatches an event, like, well you don't need to tell me the value, I just set it, right? So it's kind of weird to dispatch an event then. And if you're not careful, you might end up causing an infinite loop. So you tell the host, hey, this property changed and if the host is, if you've got like a unidirectional app setup, like you're using React and Redux or something like that, the host is like, I don't care that the property changed, my model says it's this and it sets the property and the property says, hey, the property changed and the host is like, no, and then you end up in an infinite loop, right? So you gotta be careful about that. So for these reasons, I recommend not dispatching events in response to downward data flow. So when the host sets a property and this actually differs from how Polymer does things. So Polymer is gonna fire events whenever you change properties and this is actually what powers Polymer's data binding system. But because Polymer does the additional work to guard against firing an event if you set the property equal to the same value twice and it's okay, you don't end up in an infinite loop. But if you're running just a vanilla custom element, then I don't think there's a ton of value in firing property change events. So then that leaves the next question, which is like, well, then when should I dispatch events from a custom element? And here I think what you wanna do is you only wanna dispatch events in response to internal element activity. So what is internal element activity? Well, this could be things like a user interacting with your control, an asynchronous task finishing like something loading or an animation completing, basically any time the component knows something changed and the host does not and we need to clue the host in. We need to tell the rest of the app, hey, something new has happened. This is a good time to dispatch an event and this kind of mirrors what native built-in elements do. So last recap really quick on the events. Don't dispatch them in response to downward data flow. Do dispatch them when your component has special private knowledge that the rest of the app does not have. I realize I went through all of these like super, super fast and that's because we're short on time and this is by no means an exhaustive list. Many of these are things that Polymer actually does for you already. So if you're using Polymer, it's awesome, right? You don't even have to worry about this. But I still wanted to go through the process of documenting all of these things and just trying to figure out how stuff should work. So we've been collecting all of these best practices that we've learned while building the how-to components and we've actually created a new section on developers.google.com slash web all about building components. So this is available today now. It basically takes all of our existing material around web components and custom elements and it organizes it better. So we've got API primers, checklist of custom element best practices and a few example how-to components are up there as well, demonstrating how to actually implement those best practices. So you can check this out. Here's a direct link to it. And now that we've looked at custom elements, I want to switch gears now and this is kind of where I think the talk gets a little bit more fun because I want to look at the other side of things. And I want to talk about how frameworks should then work with custom elements. And this is like a really tricky problem to solve because as you all know, there are as many JavaScript frameworks as there are stars in the Milky Way galaxy. This is not anything I have to tell you. This is science, it's a known fact, right? But I thought what we could do is we could take just like a subset of the most popular frameworks and we could write some automated tests for them and then we could publish those results to the web so we could track what does work and what doesn't work and hopefully learn from one another. And so I'm really excited to announce another project that I've been working on. This is a new site called custom elements everywhere. Making sure frameworks and custom elements can be best friends forever. The URL for this is available at custom elements everywhere.com so you can play around with this and check it out. And but you got to keep paying attention to this talk too. And I'm gonna just give you like a quick run through of how this works. So every framework on the site has a little section and in that section I indicate how many tests they're passing. There's a little write up to explain like any quirks or gotchas or anything weird like that. I've also gone through and tried to track down every web components related GitHub issue for all these different libraries so you can keep tabs on everything in one place. And of course you can go down and you can click this little button and you can view all of the tests for the framework. You can see all right, what passes, what doesn't pass so you can have a better expectation of like if I'm gonna use this custom element in pre-act or Angular or wherever this is what is and is not going to work. Oh yeah, this is where I wave my arms around and apologize. All right, if a framework is not represented here it is not because I think that framework is unimportant or not awesome or anything. I think all of them are awesome. It's just really hard to write a webpack file for every framework. I don't know, have y'all tried that? It is not fun, okay? So I have done my best here but I would love help from the community to add more libraries to this site. I really want everyone to feel like the tools that they use and that they enjoy that they are fairly represented on here. The other thing that I wanna point out is there are some known unknowns to this process. Like have I rigorously tested every feature of every framework and every permutation of custom elements? No, not at all, okay? I don't even know all the features of all the frameworks but I did wanna start just like having this starting point just to help some of these things shake out. So why don't we check out how we did? So I'm gonna go through these scores in alphabetical order starting with A for Angular and Angular actually got a 30 out of 30 in the test that I wrote. I actually was not able to write any tests that Angular failed. I'm talking about new Angular, not old Angular. New Angular, okay? And by the way, like I said, known unknowns, okay? So if some of you are using new Angular and you're running into issues, please like open a PR, open an issue on GitHub and help me track those down and write some tests. But the test that I've written so far, Angular passes all of them. Preact comes in at 24 out of 30, so pretty good, about 80%. React, 16 out of 30, so 53%, and we'll talk about why that is. And then finally, view with a 30 out of 30 again. So they're getting 100. One thing that I think is important to point out is that so far I have not encountered any major issues related to Shadow DOM so long as the custom element is kind of following the best practices that I talked about before. In the past, this has been an area where things like totally did not work, in particular with like polyfill. But these tests run in native Shadow DOM and against the polyfill. And so far, I haven't had any Shadow DOM issues. So fingers crossed, maybe we're in a better place today. That would be really exciting. Let me talk about the two areas where we did actually encounter issues though. And that was mainly around handling data, so attributes and properties, and dealing with events. And the tests for attributes and properties, these mainly check that you can pass data to an element declaratively. So using a framework's binding syntax, I can get the data into my element like I need to. And I'm kind of generalizing here, but I think roughly speaking, there's like two ways that you can think of doing this in framework land. There is what I'm calling the manual approach, where the framework has explicit syntax that you can use to tell it, hey, either set a property on this element, or set an attribute on this element, but it's sort of up to the developer to make that decision. And then there's the sort of more automated approach, where there's really only one binding syntax, and the framework has a heuristic that it uses at runtime to try and figure out how it should pass data to an element. So I'm gonna go through each of these and kind of like indicate which framework is which. So again, we'll start with Angular. This is the binding syntax for Angular. So this is how you pass data to any element or component. It doesn't matter if it's an Angular component or a custom element or whatever, this is what you use. And basically what these square brackets mean is it's telling Angular, set the foo property equal to bar, where bar is like some value inside of your Angular component, okay? In other words, my element dot foo equals bar. So not only can you pass primitive data this way, but you can also pass rich data this way. So objects and arrays, right? And that's great. Like we talked about before in the best practices, that's how we want to pass rich data. So this works really well. If you need to explicitly set an attribute for any reason, you can do that as well. You can add this attribute modifier to your binding. And this tells Angular to explicitly call like set attribute on the element, right? So you've got total options there. Angular falls into the manual bucket. You can kind of do whatever you want using their syntax. View, on the other hand, is similar, but they sort of do the inverse of what Angular does. So for a component that view creates itself, like a component just written in view.js, I believe by default, it will pass data as properties, but when it encounters a custom element, it will pass data as attributes. So that's like saying set attribute. But because view also falls into the manual bucket, along with Angular, they have a dot prop modifier that you can use on their syntax, and you can tell it explicitly pass a property to an element, which is good. Again, now we can pass objects and arrays to elements. Cool. React, on the other hand, falls into what I'm calling the automated bucket. So it has a heuristic that it uses to try to decide how to pass data to an element. Currently, when it encounters a custom element, it will always pass data as attributes. For primitive data, like a string or a number or Boolean, okay, maybe this is fine, but when we get to rich data, this becomes a problem, because when you call set attribute in React, you end up with something like this, right? And that's not very useful. Okay, I can't do anything with that. So in React, there is not a good declarative way to pass rich data to a custom element. You can work around this, so you can grab a reference to the element, and in your render function, you can manually set that property on it, but because there's not a declarative way to do it, React fails a few tests there. Again, this is more of a hiccup than a total showstopper. You still can use custom elements with React, you just gotta know about this gotcha. What's interesting is the React team is actually discussing switching this behavior to always setting properties when they encounter a custom element. So this is an RFC for React 16. I think it would be awesome if they did this, and you can check out this GitHub issue to kind of like follow the discussion. Finally, Preact. Now, Preact is interesting because Preact, like React, uses JSX, but it uses a different heuristic. So when it encounters a custom element, it will use the property on the custom element if it is defined, if it is available. Otherwise, it'll fall back to using an attribute. So the way this works in Preact goes like this. It just does like an in check. So it'll say, if foo in my element, use the property, and if it's not, okay, well, we'll fall back to the attribute then. We'll treat it like configuration. This is pretty cool, and it actually works pretty well. As a result, Preact passes all the properties and attributes tests that I've written so far. They also have a pull request that's open so that if the element that it's working with is not upgraded yet, and it's passing rich data, like an object or an array, it'll use a property then as well. Lastly, let's talk about events. So the test here, check that you can declaratively add an event listener to the DOM events dispatched by custom elements. So the way this works in Angular is anything that you put in the parentheses there, that is the event name that you are telling it to listen to. The value then is the handler to run. So this is like saying my element add event listener, foo changed on foo, okay? And the cool thing is we can use basically any event name that we want inside of those parentheses. So we can use lowercase, we can use caps case, which is good for things like URL changed or like DOM ready, right? Think of like acronyms and things like that. That'll work. Camel case, kebab case, Pascal case, my personal favorite, asshole case. Do not actually, no, no, no, no, no, no, no, no, no, no. Okay, view on the other hand is like basically the same behavior as Angular. So basically anything that you put after the V dash on directive, it doesn't matter what case it's in, it'll work in view. So view passes all the tests here. React is a little tricky because React does not have declarative syntax for listening to DOM events. So React implements its own synthetic event system that kind of like sits on top of the DOM event system. For native elements, they have a white list of events that they know to listen for, but that doesn't really work for custom elements because we could dispatch infinite different event names, right? So unfortunately this looks really tempting, but it does not work, bummer. Again, like the attributes and properties thing before, we can work around this. You can just grab a reference to the element inside of your render callback, and then using like component did mount, you can just manually add event listener. So again, a hiccup, not a showstopper, but just something to be aware of. And they do have a GitHub issue to bypass their synthetic event system for custom elements. I think it would be really, really awesome if they did this, but this is still being discussed. Finally, we get to Preact. So the exciting thing about Preact is that it uses native DOM events. So this right here totally works. Mostly, it mostly works. There's like some gotchas. The only problem here is Preact will take everything after the word on and call to lowercase on it. So like if your event was actually named foochanged with those capital letters, it would lowercase it to foochanged all lowercase and maybe never hear your event, right? So I realize you're all now thinking the same thing, which is that it means it doesn't support asshole case. And I know, major WTF. Anyway, I showed this to Jason Miller, who's the creator of Preact, and he created a pull request to add support for asshole case. I think Jason prefers to call it mixed case events because he's like Canadian, very polite, but like we all know what he means. So with that, I think we're nearing the end, and I just want to kind of like recap some of the things that we learned along the way. So regarding custom elements, I don't think there are really any rules which dictate how you must write a custom element, but I do think there are best practices that we can start to follow, which will make it easier for us to write elements consistently and easier for other developers to then consume those elements that we create. And when it comes to frameworks, the good news is that like most of what seems broken today, I think it's actually very easy to fix, and there's already issues open for most of it. And if we can generally agree on how custom elements should behave, and then in turn, how frameworks should communicate with them based on those assumptions, then I think we're actually pretty close to this cool interop framework utopia land, right? Seeing that we now have libraries which get basically like perfect scores on the test that I've been able to write is really, really encouraging. I wanna thank all of these awesome folks. So the folks who worked on how to components with me, everybody who took the time to review the custom elements everywhere site and the test, and also just like hash out these best practices with me in docs and threads and everything. These are all very, very nice people who were kind enough to share their time with me, and I really, really appreciate that. I also wanna thank all of you for spending the time to listen to me today. I'm really, really excited to see what you all build, and I hope you enjoy the rest of Polymer Summit. Thanks. Thank you.