 How is everyone doing? Good. Oh, come on. All right, so today I'm going to talk to you guys about something I've been working on and it's about web components. So component is a word that is very ambiguous these days. If you start talking to a random person who's a software engineer and you say component, after you, a lot of times you have to clarify what is a component? What are you talking about? Are you talking about a W3C web component, a React web component, Amber, Angular? We have all got components. The simple idea of a component is just you want to encapsulate some sort of view logic together. How you do that varies amongst the frameworks. Obviously, Amber has its own way. There's the Amber 1.0 way and there's the new Amber 2.0 way, which we'll probably see some sneak peeks later this afternoon about. But if we don't, I do highly encourage you to take a look at because it's a complete new way of, not complete new way, let me rephrase that. A much better way of writing components in Amber and much more performant. So, but I'm not focusing on that here. My talk is about universal components. That means not components written for Amber. So universal, used and understood by everyone. That means that your buddy who swears by React, swears by Angular, swears by whatever crazy framework of the month is, he'll be able to use your component. How many times have you been like, oh, I need a multi-select combo box or I need a table that does sorting or I need X or I need Y, whatever it is. And you go out and you can see all these results, but they're written in Angular, they're written in React, they're written in the jQuery plugin. So you'll have to wire up all the bindings yourself. It's kind of crazy what we've got ourselves in my opinion. It's kind of crazy we've got ourselves in this situation where our view layer is so tightly coupled to the rest of our application framework. We're not able to share code like we really want to. Like in the jQuery days, before we got spoiled and had all these bindings and stuff like that, in the jQuery days, jQuery plugins was how you shared code. And it was super popular, and hindsight we're all idiots, but it was super popular, it's super awesome, it still is today in a lot of circles. But I want something like that, and so basically I am declaring war on all frameworks view layers. And obviously it's a lofty statement, it's shock value. But I am indefinitely, the goal of what I'm trying to do is so that all these frameworks no longer need to have a view layer. So basically Ember would not ship with a view layer, would be my best goal in the world. Now that's long ways out and Ember has their own opinions, the core team, I'm not a core team member, so. But so who am I, why am I talking about this? I'm Jay Phelps, I'm a senior front end engineer at Netflix. You can find me at underscore Jay Phelps, the regular Jay Phelps on Twitter is taken by like a 16 year old retweets football stuff, so that's not me. I've asked him, hey, you never use Twitter, can I have your handle? And he just never replies, but then continues to retweet football stuff. So I'm underscore Jay Phelps on Twitter, but yeah, please follow me, tweet me, get in hot, debated discussions, call me a jerk, whatever. So thank you. So as many of you are probably aware, I'm not the only one who's been trying to solve this problem. The browsers as well, and there's a lot of really smart people out there. W3C, the organization that makes the standards for the web browser, mainly the HTML and CSS, they're coming up and have been for numerous years a specification to make a standard web component format. Basically, the TLDR, cuz I'm not gonna teach you all about what a normal W3C web component is, is that the browser wants to, there's a select box and it has options inside of it. It has all this special functionality and all you have to do is include it on the page. They want you to be able to build that, those type of things. So that it just HTML and it just works. You don't need to know how it works, it just works. That's the point of a component encapsulation. So there's a specification and it's a working draft. Some parts of it are very, very well defined, very well understood and agreed upon on the browser vendors. Other parts, not so much. If you've been following lately, the shadow DOM portion of it is the most controversial of all of them. The initial specification was actually shipped by Chrome several years ago and then shipped behind a feature flag behind Firefox. But the browser vendors basically just were in deadlock for several years on the specification. So thankfully, they finally got back together recently and they are re-discussing shadow DOM. For those of you who had followed it prior, then the implementation that'll probably end up actually being finalized is somewhat different, especially how you do no distribution. But that's very technical stuff. But some of the stuff is implemented today. And the stuff that is not implemented today, a lot of it you can polyfill. So with what's implemented today and what's polyfilled, what is actually possible? Can you build these awesome components that just like you can in Ember with all the awesome features that we're used to, what is it in the real world? Right now, it's not always rainbows and butterflies. So in the real world, there's a lot of things missing from the spec. Because there's a lot of things that they're like, well, that would mean we have to be really, really opinionated and we can't get a room of full of people who are from different backgrounds to agree on that. So let's look at what's missing first. And I'll give you a little hint. Can anyone guess what would be, based just off this, what's missing in the W3C Web Component Specification? Anyone just, can anyone guess, just yell it out? Yeah, there's two, someone said data biding, the other person said interpolation. So yeah, there's no interpolation of any kind built into it. Now you can roll your own implementation, but there's nothing built in. So initially, you might feel a little bit like this. And if you have no data, if you have no interpolation, that means you can't have bindings, right? Because you can't put a placeholder, have it interpolated, and then update later. So now we're going back to Spock again. And of course, here we go, no helpers, no directives, none of the cool stuff that we're used to in our view layers. So yuck. I mean, it gets us part of the way there. But we created these, we've got computed properties, observers, bindings, all this stuff that makes us super productive today, and they don't have a story for it. Not even a little bit of a recommendation. There's a template tag, and inside of it is just inert HTML, the rest is up to you. So this is how I feel. What do we do? What do we do? All right, let's start filling in these gaps. So many years back when the web component specifications came out, Mozilla started working on something called X tags. And the point of X tags is to basically create these polyfills for the custom elements and HTML imports. And then also add this very thin layer on top that adds some basic sugar, some very, very basic sugar. Now, you're not going to be able to read this, but it's very jQuery-esque how you define the components. And it's got callbacks. And it actually reminds me of jQuery slash backbone. But it really doesn't give you a whole lot. It doesn't give you the bindings, doesn't give you interpolation, none of the really fast re-renders and stuff like that. We need more. So who's the other kid on the block? Right away, out of the gun, Google came out with Polymer. And I must say it is awesome. It's got declarative data bindings. So that means that elements on your view can be bound inside your template and then update automatically when they're changed. Here's an example using Polymer.5, which as many of you know, Polymer just recently hit 1.0. I'll talk about that here in a second. But here you can see this code is actually not too dissimilar from an Ember template. You've got your curly braces that are very similar and on tap. There's actually, I think there's an RFC, or it's just been talking in the IRC group about the on tap, on click type of similar syntax. But in general, this is not too dissimilar from Ember. So let's check that off. Seems cool. Computed properties, not the same as how we do it in Ember. But I mean, it's good. You have a number property and computed squared is times number and it will compute it and save the result and recompute it when it changes. So it's not the prettiest syntax coming from Ember, but it works. So we'll check it off. It's got observers right out of the bat. Very much Sproutcore 2.0 style. The observers are automatically registered just by the suffix of having changed at the end of it. You don't have to do anything else. It just gets automatically called if you just suffix it with changed. So cool. And by the way, observers are an anti-pattern. I think Steph will be talking about that later. Here's what it looks like when you want to define an entire Polymer component. It's maybe difficult to read, I apologize. But the TLDR is that you define the tag name you want, your template and style, and then basically the class or the component that's the JavaScript that's going to wrap that and basically be your view controller. So it's pretty good. And this was out for several years, and there's an entire ecosystem of Polymer components out there. There's webcomponents.org or custom elements.org or something like that. There's an entire ecosystem of components. When you first start searching, you're like, wow, this is great. If you actually try and use some of them, a lot of them are incomplete. A lot of them don't work at all. A majority of them are not maintained. And the biggest issue is that it was an alpha. So it's a 0.5 alpha. It was more of an initial proof of concept. And bindings and re-renders and initial renders can be slow. When I say can be slow, it's always a relative term. If you're building a very simple, very simple app, like an arguably barely even an app, it's more of a website that just happens to have some dynamic functionality, Polymer would be just fine. It's not slow for very basic things. But if any of you guys have seen the DB monster example for Glimmer and those type of things where you really need to be able to push the boundaries of it because you need a giant table or you need a lot of things updating in real time. For example, at Netflix, we create real-time dashboards that have tons of graphs on them. And they're all being fed data from a web socket. And there is so much DOM manipulation, so much stuff going on. Polymer literally just chokes. It just locks the browser up. And that's the .5 version. So now, Polymer 1.0 came out about two and a half, three weeks ago. And they had basically the big thing on their really, really crappy performance was that they were polyfilling the entire Shadow DOM specification. And basically, it was fast in Chrome. Every other browser had sucked. And so now they came up with a concept called Shady DOM, which is basically like, well, what do people really want out of Shadow DOM? They want style encapsulation. And they want the ability for when you query your element, basically you don't want your elements inside your component to be mixed and matched with the elements that the consumer of your component provides. You basically want that separation. And that's kind of outside the scope of this talk. But if you're familiar with Shadow DOM, that's the general gist of things. And that made it so much faster. They actually quite literally rewrote the entire Polymer framework from the ground up. I'm sure there was maybe some copying and pasting here and there. But I followed it very closely from the .8 to the .9 to the 1.0. And it was a ground up rewrite. They're implementing their own virtual DOM. They're doing a lot of better things as far as paying attention to rendering. Because the initial version of Polymer, it was like rendering fast was like an after sight. It's focusing on everything else. And then rendering is just like, well, whatever. So it works great for buttons, works great for forms. Falls over when you try to do a giant table of data. Falls over when you try to do a chart that's updating all the time. And there are exceptions to this. But in our cases, it did. So it is fast. And this just landed. So what I've been working on, I've been working on it for quite some time. So I am evaluating 1.0 more. I still need to do some more tests. So the verdict is still out on me. But in my initial test, it still is not fast enough for me. And looking at the implementation that they're using and following the discussions, they're not secretive. But they kind of aren't as open as a community as like Ember. And they're not very accessible. I ask them a lot of questions. And they're kind of just like, kind of brush me off. Like, ah, that's implementation details. Why do you care? It's like, well, I just care. Because I want to know the future of this framework and make sure that they're not reinventing the wheel. And that's one of my biggest qualms with this. There's so many virtual DOM implementations now that React came out and really showed that the virtual DOM is one way to go that's really fast in performance. And Glimmer takes a hybrid approach, letting you use virtual DOM. But also letting you selectively re-render certain parts. You can opt into that as a tool with HTML bars. So I'm still not convinced. And so I am still going ahead with Graffiti. And my other big gripe is, where is ES6 and ES7 in this? The goal of Polymer is to be like, this is what the future is. But ES6 and ES7 is not a first class citizen. And for me personally, I'm addicted to it. I'm stage zero on Babel. And that means that I get the latest and greatest. Whatever the features are, I'm using it. And I am that type of person. I like to trail blaze. I love to get the new features. And mainly because I love to get feedback on them. What worked, what didn't work, things like that. So there's a couple of projects out there you can find of third parties trying to basically shoehorn ES7 stuff into Polymer. You can make it work. But there's no built-in stuff for decorators and stuff that I want. So what now? So several months ago, I actually do know React. And I would say Angular is the one I know least out of the three major. But I know React fairly well. And some of you may know, Netflix uses a lot of React. We use a lot of Ember, too. But we also use Backbone, Polymer. We've got the whole gamut of stuff. But on the client-side UI, like the public-facing stuff, most of it's React. And so when I was basically tasked with, my manager came to me basically and said, hey, we're duplicating a lot of effort. People are coming to our team and saying, hey, you've got really great visualizations. You've got really great components. We want that. Wow, we want that. How can we do that? And we're like, well, it was written in Ember. And they're like, well, we're using Angular. We're using React. And so you boot a separate booted actual Ember app or just pull in all of Ember just for one little thing. Yeah, you could do it or you could put it in an iframe. But it's just really not what we wanted to do. So we started looking, that's when I started looking at Polymer more seriously for some of these really hardcore situations. So I started with the knowledge that React and Ember were super fast. I knew that they were both really fast, especially with Ember with 2.0 with their Glimmer engine, which has proved itself and will continue to prove itself in performance. Actually, there's a lot to go. Basically, it set the foundation to create even better optimizations. Why is Ember fast? HTML bar slash Glimmer. And Glimmer is a buzzword. Yeah, they came up with it, whatever. But Glimmer is not an Ember specific thing. It's actually, it's a mesh of huge fundamental changes to how HTML bars works with changes to how the view layer works in Ember. So that means that it's not necessarily coupled. The whole Glimmer approach is not necessarily an Ember thing. So I went out and I said, can I use this super awesome fast thing that I know that they're going to support and thankfully the core team members are really good about separating things into separate modules that make sense. There's a clear distinction between HTML bars. There's actual tests just for the HTML bars, library, it's not perfect, but it is very, very robust. And the answer is clearly, yep, I can. So today I'm going to introduce to you Graffiti. And for those of you, I actually, in my conversations with people, I've noticed that people actually haven't gotten why I called it Graffiti. Tagging, custom tag, tag, uh, yeah, okay. Yeah, okay, tell all your friends, yep. So what is the basic Graffiti component look like? What's a simple thing? Here's a basic one right here. So we got ES7 syntax. Some of you may not actually be familiar with that. And if you're not, I really strongly recommend you, you go to Babel.io, I think it's Babel.io, or just Google search Babel and you'll find it. And learn more about the ES7 syntax and start using transpilers today. You know, start, most of you are probably generically familiar with some of it. You may just not be familiar with the class and the decorators. The decorators are the things with the at symbol that are in front of it, like reflect to attribute. But I'll really, really, really quickly run you down through this. I'm creating a class called myCounterComponent and I'm extending HTML element. Now, if you know anything about the W3C web component specification, you're not supposed to be able to do this right now. You're not supposed to be able to do this. And the reason why is because you can't actually call the constructor of a built-in HTML element class. It does illegal invocation. Thankfully, I'm a smart guy and I figured workarounds around that and the library shifts with those workarounds to let you basically experience the future when they do allow you to do that without having to do object create and set to the prototype without tapping. Basically, you had to disconnect the constructor because you didn't want the constructor to come along with it. But in this case, the constructor does get, comes along, it just becomes a no op. Excuse me. The HTML elements constructor becomes a no op. Your constructor, however, you can provide a constructor into here and it'll actually be called, which is unlike any of the other web component frameworks out there today. Your constructor will be called when you have a custom registered element. I know that sounds weird, but if you've been using W3C components, there's the created callback is the only way to, is the equivalent of a constructor in this case. But I'm trying to mock the future. So in this case, I've got a property called counter and I've got a property called backgroundColor is equal to blue. And then I've got an event here. I've got a hash. So I'm saying events equals and then I have a function called increment. And then when this gets called, it's going to increment counter. Seems fairly straightforward. So what's the decorator thing? What's that reflect attribute? Well, decorators is something coming in ES7 or ES2016, whatever they want to call it, that basically allow you to decorate a given property or function on a class or even the class itself. And what does decorate mean? It's basically just a function that gets called on the property descriptor so that you can change things to it. If you have no idea what that means, that's perfectly fine. People, library authors are going to use that crap out of this because it makes things really, really awesome. Because you can just say reflect attribute and you don't have to know how that works or what that means. By the way, reflect attribute, it means that when the property on your component when the counter property changes, the attribute on the HTML element will also change. So it'll also have a counter attribute and it will also change, which is not the default. And why is that not the default? Because sometimes you might have a property that's storing an array or storing some huge JSON blob or storing some huge string. And you obviously don't want that inside an attribute inside the DOM. It makes it very, very unperformant and also just ugly. You could opt into that behavior. So boom, we've got our ES6, ES7 syntax. Very sexy now. Some of you guys, maybe not, but some of you may notice this does look a little bit like Angular 2.0. It looks a little bit of a feedback here. Thanks. I'll speak a little louder, I think. It does look a little bit like Angular 2.0, but that's actually really just because we're using decorators. And so are they. We're both looking to the future, not looking to the past. Other than that, Ember 2.0, once we get rid of some of the crufts, Ember is going to start to look like this as well. You're going to be able to start extending and using actual ES6 classes and stuff like that. But here's the full code snippet, which before I excluded the export defaults and the imports as well. So you get your register element call. You get your reflect attribute from the graffiti library. Yeah, and that's it. And now notice the register element, I don't actually have to define the tag name. The tag name is inferred based off the class name. Now you can, if you want to call your class something else, but then call the tag name something else, you could totally do that. Pass the first parameter to the register element, and that'll be the tag name. But I really do like the Ember's convention of dry, don't repeat yourself. If I can infer something, I'm going to. So basically, the framework uses the convention. It's going to take the first part of your name minus the word component or element. So if you suffix it with component or element, it's going to take the first part and then dasherize it. So cool. We've got the class. What about bindings? I mean, I was stressing bindings. That's the big, big thing that's missing. J, bindings. Boom. Here's your template for creating your component. Now something you'll notice right away is this is slightly different than the way Ember does their templates. But it's actually very similar to the way Ember is going to probably do their templates. There's a lot of talk. There's an RFC out there for Ember. And the main difference is the root element. Notice that inside your template, you actually put your root element itself. You say my counter. And why is that cool? Because then you don't have to deal with an attribute bindings hash, where you map one thing to another in your JavaScript and all that stuff. If you want to, you don't even have to define properties. You can just go straight here and say, like background color class or background color to any of these things. You could pass and bind all those things directly right in here, all on your markup, and not have to deal with any of the property crap. The other thing about this is we've got curly braces. This is based on HTML bars. So the syntax is going to be super, super familiar to you, Ember folks. There's a slight difference because I am trying to go towards more native approaches. There's an on handler, which is very similar to an action, except it actually invokes a native event custom element. So it'll follow the normal DOM rules of bubbling. And you can disable bubbling just like you can in action and stuff like that. But it's actually a real DOM element, custom event. So if someone is using your component in whatever framework, that's how they get it. Bindings down, actions up. That's what they keep saying in Ember. And in this component, in this framework, it follows that same conventions, except for bindings down, events up. That way, it's framework agnostic. Any framework can listen to your event because you can add event listener. So in this case, I'm doing on click. I'm firing the custom increment event. And it's that straightforward. Now, going back to our previous example, notice I had put a handler on here. So I will capture that event. And the increment function would be called in this case. And it would increment counter. And the template would update. So that means that counter value right there would automatically just keep incrementing as you click the button. Very straightforward. CSS, it follows the same. And this is definitely evolving, especially recently with the new Shadow DOM discussions. There's a lot of things evolving. I'm following it very closely, and even in some of the. I'm not directly in the discussion, but I'm basically lobbying, for lack of a better word. But for now, you're going to be able to use the same syntax as before, so you can use the host pseudo selector to basically refer to the element and the component itself. And then all the styles that you put in here are actually scoped to the component itself. So that means that if you have IDs, if you have class names, those type of things, they're actually scoped and will not bleed out of your component. And also, unlike Polymer, Polymer does not currently do this. There's talks about how to do it, and they'll probably just notice my talk and steal how I'm doing it. But I actually prevent styles from bleeding in as well. So it was non-trivial to do so, but I figured out a really great way of doing it. So if you want to take a look at the code, you can. But basically, what does that mean? It means if someone says body color red, all the stuff inside your component is not going to have a color of red. So woo-hoo, your component can control its color without having to deal with that. Now, sometimes you want that behavior, right? Sometimes you want to opt into inheriting styles. Sometimes you want themability. Usually it's themability. And the direction that themability, both Polymer and this framework, is going to go is by using native CSS properties, which is outside of the scope of this talk, but mainly because I haven't implemented it yet. But also because it's very, very influx. But basically, you'll be able to say, oh, I want the kind of similar how you style a bootstrap theme. You provide variables upfront, and then all the components basically use that property inside their CSS. So I just created this component. How do I use it? What does it look like? Well, it looks like how you'd use any other HTML element. My counter, I can, if I want to, pass in a background color attribute. And I notice that this is dasherized, so it's a normal like how an attribute would normally look. But the framework, graffiti, the runtime is going to basically camelcase it so that it's going to assign it to both the attribute and to the property itself. It's going to basically, once it sets the attribute, the attribute change callback gets fired, and then it sets the property. So the difference between a property and an attribute is a really long story. But the TLDR on that is that attributes have to be strings, properties can be whatever they want. Now, sometimes their name are the same, but there's examples of class name versus class. There's the class name property, but there's the class attribute. Those are not the same. So there's a lot of confusion around about not knowing the difference. Totally OK. The framework tries to basically get rid of you needing to know the difference. And if you guys have feedback all ears, please definitely give me feedback. So once I put this on the page, page render is what actually gets output in Chrome, for example. Well, here's the example what gets output. So the class blue is there because in my previous template, I had bound the background color to be that class. And then we've got counter zero because I had said reflects to attribute. So it did, it reflected to the attribute. And then there's the background color attribute that we passed in. And then there's our template. Now, notice that the hello world that I put in here got redistributed into the label. And why did it do that? I'm going to sweep back here real quick. It did that because it follows very similar rules to the Shadow DOM specification. You use this component element. And basically you're saying, or excuse me, content element right in between label. There's a content element. And basically that's just a placeholder. The equivalent in Ember would be yield or outlet, depending on whether you're using a layout or a template. But yield would be the most effective. The syntax on this is slightly changing if you've been following. Before you used to be able to say select and then provide a selector. Now there's a new syntax for something called slots. So I am following that. And we'll be following that along and updating graffiti as things go. So all this work, what did it give me? Well, first off, it's fast. And I'm actually just scratching the surface on understanding the power of the glimmer way of rendering things. Not all of the way I'm rendering things is the most efficient it can be. Because HTML bars have two different ways of rendering. And a lot of the ways I fall back on re-rendering all the things, which is still fast, instead of just diffing just small parts. So it's going to get better at that. It's going to follow along with Ember and get that. But there's one thing I wanted to really quickly know before the end is that I'm actually using something from Angular 2. It's called zone.js. Has anyone here actually heard of this? Two people, good. So this actually is a really cool, really overlooked technology that I had never heard about. I'm not going to super explain it, but I'm just going to say that it's basically allowing me to do data binding in graffiti without needing to use object.observes, which is not supported in any browser, but Chrome. And the polyfills all suck, which is one of the reasons that performance is so poor in Polymer. But this lets me lazily know, indirectly lazily, dirty check, whether a property's changed. And it's kind of a combination of Ember's run loop with basically hooking into any possible asynchronous action that could possibly happen. So anytime data changes on your page, it's in response to something that was async, whether it be a mouse click, Ajax event, a timer. When those things happen, that's when you want to actually check, hey, did something change? Because checking just with a set interval every 10 milliseconds or whatever, nothing's changing during that time, because nothing can change. The user is not interacting with the page. There's nothing happening. So check it out. If you're a library author or if you're not, there's a really cool from NGConf video about it. But I wanted to note that there's sharing, that I'm using basically portions from Ember's core HTML bars and using parts of Angular, using philosophies from React. All these frameworks are coming together. And I see a future where they are going to blend. It's going to be a while, but I do see the future. So, yes, it is open source. As of this morning, I pushed it. So push it real good. So to get up JFelps and then slash graffiti, I'm going to be, now that it's out, I'm going to be continuing to update it. Please, please, don't feel shy about saying, you're an idiot, this doesn't work, or this is bad. Why are you doing this? It is super alpha. So I'm warning you, don't use it in production. If you use it in production, it's not my fault if it breaks. That being said, Netflix is going to possibly invest heavily in this technology in the coming future. Basically, it's in the R&D phase, and we're trying to basically decide, is this really, we're kind of getting our feet wet in it? And if we can really figure out this story, we're going to invest heavily in it. So your input is definitely desirable. So please let me know. So contributions are very much welcome. And I do want to give a really quick shout out to the Ambercore team, particularly those that let me bug them about HTML bars and glimmer. Where's Matthew Beal, McSonic? Can you stand up real quick? Can you guys give him a round of applause? And then, like, Yehuda's not here, but Yehuda's a very hard man to get a hold of. But thankfully, he's very kind, and if you're persistent, and explain why you're trying to get a hold of him, he will talk to you. And he helped me a lot. And mainly because the changes that glimmer made completely flipped HTML bars on its head. So I got lost. Because I initially implemented this months ago using old HTML bars. And then when glimmer came, I was just like, I don't even, what is this? What the heck? Thankfully, you guys don't have to deal with that. And that's all for my talk. So I don't know if I have time for a Q&A. Yeah? Please use the mic just so we can hear your questions. Hello? OK, any questions? So I couldn't tell. Is this integratable? Like, does it need some sort of control over execution? Or is it integratable? So could you render in your Ember app, just render a graffiti component tag, and then it would work? Oh, sorry. Yeah, I guess I should have probably put a stupid Ember demo. Yes, the entire point of this is that basically the consumer of your component does not need to give two cents a crap about how you implemented this, whether it's what it's using HTML bars, how it does any of its stuff. That's all abstracted. They use it just like a normal HTML element. So that means that even if you're on a big team, maybe you're not. But if you're like Netflix, you're on a big team, and you've got guys who just do server-side MVC with grails or whatever have you, they can even use these components. They just have to include your bundled JavaScript. Basically, it gets compiled down to a single JavaScript file you include, and it will automatically register it with the DOM. And they just have to use the element just like any other element. Now, there's caveats to that in the sense of if you are trying to pass non-strings to a component, because of attributes versus properties thing, if you're trying to pass an array or an object, you do have to actually use the properties themselves to do that. Now, integration with Ember is actually going to be perfectly fine, because it has, I don't want to say props first, because we're probably changing it. McSonic and I have been talking about this a lot. But in the Ember ecosystem, it's going to just work out of the box. You're going to be able to pass arrays and objects and whatever you want to these components. And it just works. It'll just work. You won't have to do anything. It's just going to work. React, I had a lobby for some specific changes. And thankfully, as of last week, I can say that the Canary branch does work with Glimmer. The main issue was custom attributes. They did not support custom attributes, which is insane. But I know why, but it's insane. So now it works in Canary, and they're going to be cutting a release whenever they feel like it. You guys don't care about that, though. So yes, so you use it just like you'd use any other HTML element, except for those cases where you need to pass non-strings. You need to use the properties, not set attribute. Does that answer your question? Great. And by the way, if interest does pick up on this, and because I'm primarily an Ember person, like my day-to-day, I do a lot of Ember, I do plan on creating an add-on that will let you use an Ember CLI add-on that will let you put your graffiti components in with your Ember app, and it will transpile them with it so that you can also, fingers crossed without too much hackiness, use roundable components into a graffiti component. So theoretically, you could actually write your entire views in graffiti and not even actually use an Ember view, but there's caveats to that, and I can't promise the entire story. But there definitely is going to be an add-on for it. Question? Hi. Yeah, I have a question about the way that events work. So they bubble up in the DOM. So if you have a parent and a child, the event will bubble up, and you can just put a listener function in there. If you had sibling components, is there a way to get them to talk to each other? That is how you communicate. Just like you'd communicate with actions, it works the same way. You could, I didn't show it in here, but very similar to actions, there's a way of curing functions to an event, and you could basically, you could tell a component, like a nested component, hey, trigger this event when I click you, or whatever, or win save, or whatever. And it will actually trigger that native event and bubble up, and then you can capture that in your parent component. So really, it's almost identical to how actions work, except for it's not an abstraction, and it also doesn't throw, the major difference between an action and an event is that, like a native DOM event, is a native DOM event can fire and forget. Like it can happen, and there's no, like it can not, no one could catch it, and it's OK. Whereas an action, if it's triggered and no one catches it, that's an error. It's basically saying you have to take an action on this. And why that's OK in Ember is because if you write your components correctly, you're supposed to opt into them sending the action, not to have the action sent by default, in most cases. But other than that, it's going to work very much like Ember. OK, I think we'll cut the questions there on the interest of time. Jay, thank you very much. Thank you all.