 Good afternoon. Hello. So my name is Steven Fluen and I'm a developer advocate on the Angular team. Hi there. My name is Rob Dodson. I'm a developer advocate on the Chrome team. And today we're going to be talking about using web components with Angular. So this is a topic that Steven and I get asked about a lot. So we thought it would be cool, this I.O., to sit down, do a session, highlight how you can combine these two technologies and cover some of the best practices for doing so and also where we see the best opportunities for doing that. But before we get started, we just want to do a quick overview just to throw out some terminology, familiarize everyone, make sure we're all on the same page, and explain again where we think these two things fit well together. So Angular is a platform that makes it easy to build applications with the web. And I talk about this a lot with developers. And I use these two terms very particularly. I use the term platform to refer to Angular because what we're really trying to do is we're trying to move from being a framework into a platform that owns the entire end-to-end developer experience. And I use the term with the web very intentionally because while you can build Angular applications that target installed mobile or desktop use cases, we're really built from the core with the web and for the web. And when we talk about web components, we're talking about a new set of APIs that are landing in the browser that allow you to define your own custom HTML tags. And these are tags, components, if you want to call them that, that will work really in any context with any library or framework. That's really our primary goal there. The two big standards that make up web components are custom elements. That's what lets you define your own custom HTML tag. And Shadow DOM, that's what lets you scope your CSS and encapsulate your markup inside of those controls. Many of you are also probably familiar with libraries like Polymer, which we use to build web components. Today, we're actually not going to be talking about Polymer specifically. The reason is because I wanted to sort of remove variables from the talk and make sure that I could just get down to just the web standard level with vanilla JavaScript and make sure those worked well with Angular. Once we have that stuff squared away, then adding in libraries and abstractions becomes a lot easier. So let's talk a little bit about why we would want to combine these things. Because there are two technologies that are playing a little bit of different roles. So we talk to a lot of companies and a lot of enterprises that are using many, many different technologies. And these companies are often building lots and lots of apps across different sub teams and different divisions. This is kind of a very common problem among enterprises large and small. And what ends up happening is a lot of these companies end up wanting to have a single UI library, whether they're building a date picker or some sort of calendar or even just a normal data table. They want to be taking UI standards and brand guidelines that are coming from the company and apply them to the technology that they're using across the board, regardless of what framework or pieces of technology that they're using. So when we think about these two things, we think that Angular is great for structuring and organizing an application. Whether you're looking at something like the CLI, which is going to help you scaffold and get started with a project, as well as build and ship a project. Or whether it's other tools within the Angular framework that are really all about architecting and thinking higher level about the application and the flows within your application, Angular is great at those pieces. But web components is really great at compatibility and building reusable UI elements that can be used across many, many different contexts. So then you might be asking yourself, all right, well, that sounds good. But doesn't Google have multiple implementations of its UI library? And how come you all aren't really walking this talk? So it's true. We actually have more than two versions of our UI library . We have one in Polymer and web components. We have one in Angular. We have things like material design light and material components. There's even a few internal implementations sprinkled around there. And the reason is because when we started material design, I guess maybe three plus years ago at this point, when we started material design, the web component standards were very much still in flux. Today we have web components v1. We have it shipping across Chrome, Opera, and Safari. Things are starting to settle down now. And I think we're actually at a place where we can start to take a serious look at how we can share work across all these different teams. I also want to point out, because people ask this a lot, they ask, is Angular on Polymer? Are these going to merge together? Are they going away at some point? How's that going to work? So there's no plan for any of these projects to go away at any point. They all have their own priorities that they're trying to solve. But we absolutely want these things to be able to interoperate well. So it's a primary goal of web components, that they should be able to work anywhere. And I know that a lot of effort went into the Angular rewrite to make sure that web components were well supported. And so to demonstrate this, what we've done today is we've put together a very simple application, which we hope highlights some ways that you can integrate these two together. And that's really what we're going to be walking through with you today. So what we've built for you is a simple checkout form. On the left side, you see two standard HTML inputs where you've got a name and an address for the user. And then we've got two web components below that, a list box over on the left side that's going to be accepting information about how the user wants to be shipping their products. And then a checkbox that allows the user to decide whether or not they want gift wrapping for their product. And on the right, we've got all of these Angular declarative templates that show, hey, here are the prices that we're going to be using. Here's the subtotals. And then giving the user the ability to submit all of that information. So there in the bottom, you can see the shipping selection. And then below that, you can see the is a gift wrapping web component that we're adding there. So our agenda for today, as we're going to go through this session, is really going to have four parts. We're going to talk about how to set up an Angular project and make it compatible with web components. Then we're going to talk about the guidelines and the best practices for authoring your web components in a way that can be compatible with frameworks. Then we're going to talk about how do you use these web components within Angular. And we'll finish it up with some general best practices. So let's get started here with a project setup. So within this context, I'm really talking about using a Angular CLI project. So using the at Angular slash CLI project within NPM. And so let's dig in. By NPM, I'm going to NPM install Angular CLI. And then I'm going to use the ng new command in order to scaffold out that project within my system. Then I'm going to CD into that folder and I'm going to see all of the things that it created for me. A CLI project looks a little bit complex at first, but it actually has all of the things that you need to get up and running as a developer using Angular. So everything from editor configurations, git configurations, typescript, environmental configurations, as well as tests that make it easier to maintain your application as it continues to grow. And then in the source slash app folder, we're going to really see the core of my Angular app and the code that I'm going to be writing, where you can see all of my modules, my components, their typescript, HTML, and tests. So then now that I have a standard Angular project that's going to work for me, I'm going to go ahead and add the polyfills that I need to work with web components. So we've released these tools on NPM and so I can use NPM or Yarn to yarn add at web components slash web components.js. And then we're going to go ahead for our project and we're going to add two specific components called dash checkbox and dash listbox. Then within my Angular project, I'm going to go and find the polyfills.ts file. This is a file that has a built-in tutorial that says based on what browsers you want to support, based on what targets you're going to target, here are the polyfills and the other pieces of JavaScript that you're going to need to include in your project to make everything work. So within there you're going to see the import for zone.js, which Angular is dependent on for change detection. And right below that, I'm going to go ahead and add the web components polyfill that's going to make my application compatible with web components. So one possible foot gun that you might run into as you're at this phase in your project is that if you're transpiling your elements down to ES5, your custom elements down to ES5, in browsers which natively support custom elements already, like Chrome, Opera, and Safari, by sort of spec definition, those browsers expect a custom element to be an ES2015 class. You try and give it an ES5 object that you've created and say, hey, let me call custom elements defined with that. It'll actually break. And so if you're transpiling your entire application and you're loading it into a browser that already has native support, you need to include a little ES5 shim. It's kind of weird to think about it. You're taking your ES5 code and backing it into the future if you want to think of it that way. But here's how we did it in our project. We included this little snippet here. So if the browser has native support for custom elements, it's going to load the adapter. Otherwise, the adapter is going to self-remove itself. This is probably something that you could just sneak into a webpack plugin or something like that so you don't have to look at it. But I did want to make the snippet available. And yeah, if you want to write a webpack plugin out of this, that's a free open source project idea that I would love to see. So now let's go ahead and add web components directly into our Angular project. So I'm going to do two things within my app module. The first is I'm going to go and import those web components in their ES5 or ES2015 version. Then I'm going to go ahead and let Angular know about web components that I'm using them within my application. So I'm going to import custom elements schema and I'm going to supply that as a schema on my root app module. And what this is actually going to do is normally Angular goes through all my templates and validates and verifies as part of compilation that every HTML tag I use is part of the HTML spec or coming from a component that was within the context that I know about. And what adding this custom element schema does is it turns off that validation so that we're able to add any generic web component to our application without throwing additional errors. Then for our project here, we're going to take a very simple Angular form. So you're going to see that at the very top we've got a submit event that we're using for event binding. We're using ngforms here. So we're going to assign that out to a variable. And then we're adding this HTML input tags with ngmodel directives on it. And those directives wire up the form for us. And then we've got the shipping web component that we're going to be adding a little bit later. And then we've got the gift wrapping web component we're going to be adding. And so what do we really want from forms as a user? So as a user, I really want to turn forms from a one-way data dump into a conversation that the application can be interactively telling me about what's going on with the form in a more helpful and intuitive way. One of the problems with building web components by default today is that you have to wire up forms yourself. By default, they won't be included in the value of a form element. But because Angular automatically and is already doing all of that rewiring to make all of the submit buttons work and all the keyboard shortcuts work, we can include web components in that model very easily. All right. So now that we've got some placeholder spots in our app where we're going to include some components, it's time to actually go through and do a bit of our authoring. Now, I've split this into two sections. I want to talk a little bit about custom element philosophy, basically like what I think makes a good component. And then we're going to walk through how do we define an interface that works well, not just with Angular, but really a custom element that works well with any library or framework. So yeah, component philosophy. What makes a good component? I'm going to say first and foremost, if you're building web components to be used inside of an Angular app, I feel like these components work especially well as leaf nodes. So you can think of leaf nodes as stuff that you really can't break down any further, right? Stuff that's pretty concrete UI. If you were to graph the structure of your application, these would be sort of like the terminating nodes at the end of that graph. You're already familiar with using leaf nodes in HTML all the time. Most of the interactive controls that you use are already leaf nodes, so things like button and select and input, things like that, right? You don't think about breaking those down into any smaller pieces. They're kind of as small as they get. Another way that I like to think about this is these are not abstractions, right? They're really concrete pieces of UI. So using Angular, you might create a more abstract view, like user dashboard or login view or something like that. And that view will be made up of these smaller, more concrete UI components. And that's a good place for web components to slot in. I also try to take any component that I'm building. And if it's too monolithic, I want to figure out how I can break it down into smaller pieces and factor it into these little bits that I can compose together. So I want to show you what I would sort of recommend not doing and then what I prefer when I am structuring my elements. So let's say I'm building a list box. And I've totally done this before. I started building this element and I was like, all right, I guess the API for this thing will be, you got to like select it in JavaScript and maybe there'll be like an array of elements and I'll call a method on that element and I'll give it this array and it'll render all that stuff in the shadow DOM and like, yeah, that's how my list box is going to work. I've totally built controls that work this way. There's some downsides to doing this though. For starters, we've got to have some imperative JavaScript setup code there. We've actually got a query for this element and call a method and pass some data to it that way, which is a little funky. Also, we're hiding all of our content in the shadow DOM and we don't need to be. So instead of doing that approach, again, we want to take that monolith so this dash list box can have little dash option children inside of it. That way we can put the content right there in the light DOM. That's good for crawlers and bots that want to, you know, read the page. It also means that you can just hand author this in regular HTML, right? I don't have to do any imperative JavaScript setup code to get it into this state. So, yeah, it's good for server rendering the thing. If you want to think of it that way, your content is in the visible DOM so it should be able to be crawled in. Another thing that I like to do is I like to think of web components as each one as like its own little sealed black box. Kind of the same way that you think of native HTML as like a sealed black box, right? You don't try and poke around in the internals of the select element or anything like that. And so when you're working with web components, you don't want to try and like pierce the shadow root or violate the encapsulation or anything. You know, when we work with native HTML, there's a very well-defined interface that we use for talking to those controls in our web components. So that means we use attributes and properties to configure the control, and then we listen for events to, you know, signal changes in the control. And if we make sure that our custom element dovetails into this pattern, then we'll have a nicer time working with other libraries and frameworks which are already sort of built to understand this. So finally, I would say whenever you're building a component, I try to recommend preferring a properties-driven interface on methods and things like that. Let me give you kind of a more concrete example of what I mean there. So let's say you're building a dialogue element. It's very tempting to say, okay, I've got this dialogue control, and I guess the only way for it to render in its open state is going to be for someone to query for it in JavaScript and call this like open method. And that's how you'll open the thing, right? And I would recommend instead of doing this, give it an open property and have setting that property, render your open state. There's a few reasons why this has been official. The first is it means that state can be very easily reflected onto this component. So if you're using like a unidirectional data flow, sort of like what Angular does or what something like Redux likes to do, where you want to take a state object and just kind of like pass all those props down the tree, this model works very well for that. It also means that someone who's just writing vanilla HTML can very easily configure your control. They don't have to write any JavaScript to open it. They can just put an open attribute on the thing and send its open state, right? And as you start to do this and you look at native HTML, you'll see there's a lot of similarities there. Things like the checked element or the input type equals checked element. It has a checked property and a checked attribute. It doesn't have like a toggle method or anything like that. So as we're mirroring what native HTML does, it tends to make our life a little bit easier. So with all that in mind, let's actually create an element and define an interface that matches these patterns so I'm just going to build this little check box here and for the sake of time, I'm not going to cover every detail of how we built this element but I do want to highlight the important areas of integration between Angular and Custom Elements. So I've got two goals. The first is I want to make sure that Angular can tell my element what state to be in and the other is I want Angular to be able to listen to changes from my element. By satisfying both of these, I should be happy. So let's start with that first item there, making sure Angular can tell my control what state to be in. So I'm going to start by creating a Custom Element class and under the hood, Custom Elements are a really, really simple API. You basically are just associating an ES2015 class with a tag. You're telling the browser, hey, whenever the parser hits one of these tags, create an instance of this class. So I've got a dash check box class that extends from HTML element. I call Custom Elements define, I tell it the tag name, I give it the class that I want to associate it with and with just that, I've created my own HTML tag. I've extended the language, which is pretty cool. But right now it doesn't really do anything. So I'm going to add a little bit of behavior to this and again, the interface that I want is one that kind of maps back to what native HTML does here. So I've got a checked property that could be set or a checked attribute. I want to keep these two in sync. So setting one sets the other vice versa, right? To do this with a Custom Element, very straightforward, I can just use regular old property getters and setters on my class to synchronize with my attributes. So inside of my check box, I'll create a set checked setter and a getter for checked. And I'm checking in my setter to see if the value passed in is truthy. This is very similar to what native HTML does because you can pass in strings and stuff to the input type that will check element and it'll say it's true. And then I reflect that to my attribute and since it's a Boolean attribute, I'm either going to set the attribute or I will remove the attribute entirely. The interesting thing I think is the getter. So the getter is checking to see if the attribute exists and that is how we're defining the state of the property. The interesting thing with this approach is that means if someone goes in and they just remove the attribute, then the property immediately becomes false. I don't really have to write any additional code to keep these two in sync, which is pretty handy. So now Angular can go in and can set either an attribute or property, whichever approach we want to use there. So I'm going to remove the check property and figure out the current state of the control. The next thing is we want to tell Angular anytime something in the control changes and I have a little rule that I try and follow with all of my custom elements when it comes to doing this. So I want to dispatch DOM events when things change but I like to do this only when there's some external force acting on the control. So a user clicked on it or something loaded or a timer fired within it or something like that. I tend not to do this. So I'm going to do this and I'm going to dispatch events just because someone set a property on me. My assumption there is if the developer set the property, they know they did that and they don't need an event telling them that they've done that. It also avoids potential issues with any sort of binding system that is property and event driven. You don't want to end up creating infinite loops where it's setting the property and hearing the event and setting the property and so on and so on. So inside of my connected callback this fires anytime my element gets inserted in the page. This is sort of its initialization phase. I can add event listeners for user clicks or key down, anything like that. In this case, I've got a toggle check handler. Inside of there, I'm just going to flip my check state which triggers my setter which sets the attribute and I also dispatch an event telling the outside world, hey, something changed. The event name that I chose there of change was very specific because there's some upsides for doing that when you're working with Angular. So now Angular can tell my component what state to be in. It can listen for changes from my component. Again, I've got sort of this interface similar to what I showed before where I've got properties and attributes going in. I've got events coming out. We also have another element inside of here, this list box control. And for that, I did basically the exact same thing. I defined a little properties interface for a value property and I fire an input event so it's sort of more like a generic input control there. And we'll also talk about why that's beneficial in Angular in just a second. But with these two items satisfied, our custom elements should work well pretty much anywhere and so the last thing to do is just to bring the two together with our Angular app. All right, let's go ahead and look at how we can now add these custom elements that we've developed within the app that we set up earlier. So we're going to do three things. First, we're going to bind to those elements. First, we're going to go ahead and add ng model support using forms. And then we'll talk a little bit about validation and how that works. So starting with binding to elements, I'll take that same form that I set up a little bit earlier and I'll go ahead and add in my dash check box. And you'll notice that this looks very much like Angular where I've got the square brackets for property binding right on my web component and we're setting the checked. And by setting the checked property, that's equivalent to running the check box. So we're going to go ahead and add the component that we've got and we're pulling out the property isGift and we're assigning it out to that check box. Now let's actually add the listener. So now we're going to listen for that change event. So we're manually wiring up the event listener and now we're going to set the isGift property on our component to the event's targets checked property. So now these things, basically we have a check box that when we click on the isGift property, we're going to run change detection and render the new state of the app. So this is how we manually wire things up, right? I use the property attribute binding to set the properties and I use the event listeners to bind to all the events that the property is going to emit. But that's not actually the easiest way to do it. We want to be using Angular forms. So Angular forms are really based on this idea of an ng model where we can look at a component or a control and set the attributes and properties and we're going to be listening for events. So let's look how we do this with standard HTML. With standard HTML, for example, with an input tag, we're going to be setting the value property and we're going to be listening for input events and we call this the default value accessor. Most of the time you don't see this because it's under the hood, but there's some ways that we can tap into it now that we're using web components. And then if we look at a check box, we're going to be setting the check property and we're going to be listening for change events. So within Angular, we call that the check box control value accessor. And so while these things work perfect for standard HTML elements, we can actually do the same thing with custom value accessors. So if I have a web component that has the same API as a standard input tag where I can be setting the value property and listening for input events, then I can just reuse that default value accessor on those components or controls. Now, if I have the same properties and same API as a check box, I can still use that check box property and the change events from it using the check box control value accessor. So let's take a look at each of these. So in my dash list box, which matches the API of an input box, all I have to do is add the directive ng default control along with ng model. And with this, it tells Angular and Angular forms the API that it needs to use to listen for changes and to set and update. Then we can even do things like stamp out additional dash options using standard Angular syntax such as ng4. So here we're iterating through a list of shipping options and we're printing out that option with the value being set to that option, one for each of those within our web component. Now if we turn our glance a little bit over towards the dash check box that we built, maybe we want to build a completely custom value accessor and we can do that too. This will allow us to engage and interact with any arbitrary API that we need maybe from a web component that we didn't offer, that we don't control. So I'm going to wire it up within Angular using a directive. So I've got the selector here for dash check box. I'm going to add a host event listener on change where we're going to be looking at the checked property of that changed object. And then I'm going to let Angular forms know that we have a value accessor for this by using a provider that points to this property. So in this example, we define that dash check box directive. There's a few methods here. We have a property called on change, which is the function that we're going to be calling. Then we have a constructor that gets us access to both the element and the renderer that Angular needs to do these sorts of interactions. Then we have a method that's going to tell us how to write out that property and then we're going to register ourselves to listen for those change events and then we'll also register for touch events. Angular forms are a magical experience in my perspective because the moment you've wired up these control value accessors, everything that you expect from a form validation standpoint is just going to start working. So if I take that same dash list box that we built and I add a required attribute to it, it's now going to be required as part of the standard form controls. And within Angular forms we actually give you a set of CSS classes that let you know what's going on within your form. If a control has been visited, you'll see NG touched or NG untouched. If the form's value has changed, we're going to see NG dirty. And you can tell whether or not the form itself or the form controls are valid. And all of these things are wired up automatically using the validators that you use. These are the same validators you use with standard HTML elements. And then combining that with the requirements that you've set within your component. So now, as I hit Submit here, for example, if I hadn't filled out any of these fields that we'd marked as required, I'm going to see the same CSS classes applied to all of these things. So let's now talk a little bit about best practices for combining these things. First of all, staying up to date. Second, using ES2015 imports. Third, mutating data. And fourth, theming. Now let's dive into each of these. So the first thing that's very important is staying up to date. The web component spec itself recently hit version one, but it's continuing to be revised and updated as they move and look towards a version two possibly in the future. As well, Angular is continuing to be updated. Between versions two and four, we actually made a bunch of different improvements that improve compatibility across the board between Angular and web components. And we're continuing to look at ways to do that. There are other things that are happening across the web as the ecosystem evolves as well, such as the fact that we, on the Angular CLI, give you a certain set of polyfills. And we can help you manage those polyfills as things continue to evolve. Because I think we all hope for a world where we don't need polyfills because the web standards have evolved sufficiently. Additionally, we're really talking very specifically about a couple versions. When you go all the way back to AngularJS, we didn't have the same sort of approach that we have now and the same sort of knowledge that we have about web components and the specs that exist. And so AngularJS is much more DOM bound. And there's a little bit more magic under the hood in terms of how we interact with elements. And so working with web components is not as great of experience, and you can run into edge cases. Whereas if you're using Angular, any of the latest versions, you're going to have a much better time, especially when combined with the latest Polymer 2 or anything from the web components 1.0 spec. Yeah. So the next thing we want to talk about is how you use ES2015 imports with these controls. So using ES2015 imports with Angular is pretty nice, because Angular CLI gives you a nice build pipeline to go ahead, bundle and package these things up. You've got great tools out there, things like roll up, which will do tree shaking and things like that. So it's really, really exciting to be at a place now where we can start using this technology. But I know if you're, you know, some of you are already familiar with web components, you might be wondering, OK, cool, ES2015 imports. What about those HTML import things, right? Those are part of the web component spec as well. So while HTML imports have shipped in Chrome, and they're still totally safe to use in polyfill and other browsers and things like that, I think it's probably unlikely that other browsers are going to ship HTML imports in their current form. I think instead the direction that the specs are taking is one in which HTML imports will probably be reimagined on top of the ES module loader system. And that's a good thing, because it means we don't have two systems for how things get loaded into the browser. So, you know, today, if you're building vanilla web components, I think it's totally OK to just go ahead and use ES2015 modules for those. And that brings up two more interesting points, which is how do you transpile those modules and how do you publish them to something like NPM? So this is the approach that we use in our project. I'm not going to say whether this is right or wrong, but this is what we did, and it seemed to work for us. What I'm doing here in my package JSON for my element is I'm creating a number of different build artifacts. I'm exposing those to the user so they can kind of choose which one they want to leverage. This is similar to the approach that the Angular team uses when they publish their own libraries. So what we're doing here is in our package JSON, main points at a fully transpiled, bundled together ES5 version of our component using UMD. So this should be able to be dropped into the page using a script tag or loaded with common JS libraries like Browserify and things like that. This one should work pretty much anywhere. For folks who want a little bit more control, there's also a module field that we've dropped in there. So this is still transpiled to ES5, but we're using module syntax for import-export. We left that in there. That's so a tool like Rollup can do tree shaking if it wants. And so, again, if someone wants to have a bit of a fancier build, they could rely on that. And we've also got an ES2015 field. This is basically just well-supported ES2015 with import-export syntax left in there. So this is for someone who wants full control over their dependencies. They want to build what's inside of node modules maybe. And they want to have differential serving for different clients depending on what they support, things like that. So this is an approach that we used. You can do this in your package JSON or maybe put it in your Bower JSON. If you want to learn more about this, the Angular team has put together a pretty good write-up over at the Angular package format doc there. So you can learn more about that. Personally, I would love it if I could publish my components as ES2015, and that would sort of be it. I know the Polymer team is excited to do something like that as well in the near future. But for a tool like Angular CLI today, you kind of need to publish as ES5. I don't even think it allows you to transpile what's inside of node modules. And so we're definitely at a point now, and this goes way bigger than this talk, but we're at a point in our community, we've got to start figuring out like, how are we going to eventually transition off of publishing everything on MPM as ES5 so we can start adopting ES2015 more, especially because many of our client browsers probably already support most of the ES2015 features we want to ship to them. So yeah, you can check out this doc for a little bit more backstory there. Also, some of your ears may have perked up a second ago when I said Bower JSON, and you may have been like, wait, what did he just say? So I know for the web components people, you're like, oh yeah, I'm used to that. For the Angular people, you might be like, hmm. So there is still a lot of utility in using a tool like Bower for package management, particularly for web components. The reason is because when you're working with custom elements, the tag names are global. So you can only have one version of a tag registered at a time. It means if you can't have a fancy button V1 and fancy button V2 living on the page at the same time, you got to pick one, okay? So a tool like Bower is helpful here because at install time, if there are version conflicts, it will ask you which of these versions do you want to use? It'll deduplicate, and therefore your client dependencies, you're only going to be shipping one version of that library. And ultimately, this is a good thing, right? Like we don't want to ship 12 versions of Lodash to the client, though I have seen people do that before. So deduplicating is good. It saves bytes over the wire. But I realized that everybody wants to use Bower. So if you want to use a tool like NPM for publishing your web components, you can do that as well. My recommendation there would be to rely on the peer dependencies field in package JSON to express your dependencies and avoid version conflicts that way. So the way that that would work is, let's take our list box here, which had that dash option child that it depended on. So if it says, hey, that's a peer dependency of mine, then when someone runs NPM install, it'll install this element, and then it'll log a little warning in the console and say, hey, you've got an unmet peer dependency. You need to install dash option at version 1.0. So this'll give you a nice flat structure in your NPM folder. The downside to this is, it's not going to install that dependency for you. You've got to manually do that, which means you've just become kind of a one-person package manager. So it's workable in the near term, but I think we can do a little bit better there. The thing that I'm kind of most excited about right now is the yarn package manager. In particular, the flat option that yarn has. So this lets you do a flat install. It's basically giving you that same bower behavior where you kind of deduplicate your dependencies, but you can still use things like the NPM registry, which is pretty nice. A word of warning. This is pretty experimental. I wouldn't recommend actually doing what I'm about to show you in your project, but it's interesting and exciting, and I want people to explore this space, okay? So here's how it works in yarn to flat install your client code. If you're vending a custom element or something like that, you can put a flat field in its package JSON. This says, hey, when you're installing this thing, it must be deduplicated. And then inside of your project, when you run yarn install, you pass it the flat flag, and that says, all right, anybody with flat in their package JSON, make sure to deduplicate them. Resolve any version conflicts that I have. When you think about it a little bit, your dependencies, the stuff you want to send to the client, yes, deduplicating that stuff is good. Your dev dependencies, your build tools, and things like that, that stuff you can probably leave with the whole nested node module structure. It's probably fine. So if you want to take this a step further, what you might consider doing is actually separating your client-side modules and your build tool modules. So you could pass additional flags to yarn where you say, all right, the production flag, these are my dependencies. I want them installed in actually a separate directory called client modules, and then I'll let all my build tools and all that other stuff, that can keep going in node modules. Again, very experimental. I wouldn't do this in production just yet, but I'd be really interested for people to try it out on some side projects and see if it works, if it doesn't work, and let me know kind of where you find issues there, because I'm pretty excited about this approach. Yeah, sorry, TLDR, Bower, if you can stand it, it is sort of helpful with web components. If you want to use NPM, peer dependencies got your back. And then finally, experiment with the yarn install stuff. I'm not quite sure about flat installing today, but in the near future, I hope we can make that a workable solution for folks. So another common problem that we end up seeing when we're combining these things is about mutating data. And so we've done a ton of work with Angular in order to handle change detection of content and data. And so if we take an example scatterplot data set like this, if we make a change to one of the names in the first items of the array, by just a simple inspection of the root, you don't actually know if anything's changed, right? We can't easily check data without comparing the entire tree against it, another. This happens with both arrays and with objects. In an Angular, we solve this with change detection that's all based on users and a very fast one-way data flow, or excuse me, change detection, passed across all of your components in your tree. But when we add in Polymer elements, or excuse me, web components, this can actually be a little bit more difficult. And so if we take, for example, an X scatterplot element here, what we actually want to be doing is we want to be making a copy of that object using something like object.assign. And by making a whole copy of that object, we'll get out a new array and then your web component can do a very simple, is it this exactly equals to the other thing? And if it's not, then it knows it needs to re-render itself. And so this is a relatively straightforward way that solves change detection that mirrors a lot of the things that we're doing with an Angular. Last thing we want to touch on is theming. This comes up quite a lot when people are talking about web components. So there's really two approaches that you can use here. If you're not ready to dive headfirst into Shadow DOM, you can just write a custom element. And along with your JavaScript file, you can bend a CSS file. And you can say, hey, if you're going to use this component, here's the CSS for it as well. Kind of like the way we used to include Bootstrap in a lot of our projects. It's a totally workable solution. And in fact, it's how we included the checkbox in our example. So Angular CLI does a really good job when you're importing styles of just putting those together into a style element for you and injecting that in the page, which is really nice. So yeah, we have a dash checkbox CSS. We have a dash checkbox JS. We just import both in the project and we're good to go. If you do want to use something like Shadow DOM though, the upside there is your element will be a little bit more modular. You can maybe use it in more places. You don't have to run the risk of overriding its styles or anything like that. So the approach that I use when I'm just doing vanilla web components and I'm working with Shadow DOM looks like this. So I'll create a template element up at the top there. Inside, I'll put using just inner HTML, like a template string for my entire element. And then inside of my actual checkbox element, what I can do then is clone that node during connected callback and insert it into my shadow root. The upside of using this approach, versus just calling inner HTML on your shadow root, is that this will save a lot on HTML parse cost because we're parsing it one time up there in the template and then we're just cloning that DOM over and over into our elements. This is a little perf when if you want to use this pattern. To look at that template a little bit more and look at the actual style inside of there, if we want someone to be able to theme our component, then we need to expose styling hooks for them. We can do that via custom properties, aka CSS variables. So in this case for my checkbox, for the border that goes around the checkbox, I can expose that as a checkbox border color CSS property. Now anyone can set that higher up in the page. If they don't set the property, then I'm providing a fallback value there. So my checkbox border will be black by default. So this is about as good as it gets when it comes to styling vanilla web components today. There's a lot more work we want to do in the standard space to make theming easier. But today, custom properties are probably your best bet. Oh, I also want to point out, I'm not showing how to work with the shady DOM polyfill directly in any of this code. And there's a couple of places inside of your custom element where you need to shim styles for legacy browsers. My recommendation is if you're at that point and you find it sort of onerous to work directly with the polyfill, that's a good time to consider using a library like Polymer because that's exactly the kind of thing that it does. It sort of cleans up that boilerplate code for you so you don't have to do that repetitive stuff. So let's go ahead and wrap up here. So we've walked a little bit through how to combine both Angular and web components and we can see how these things come together in some very natural ways that are very beneficial to each other. Really, one of the things to consider is consider your audience. What tools are your developers using? If your developers have multiple teams on multiple stacks, that can be one of the drivers that can make you say, hey, maybe we should consider web components in our project. So we're gonna be pushing the demo that we showed here live very shortly after this talk. So we wanted to thank everyone for coming and if you have any thoughts, if you like the way that we've talked about and recommended integrating these two things, let us know or if you don't like it, we're both available on Twitter. And once again, thank you guys so much for coming. Hope you enjoyed IO17.