 Hi, everyone. So my name is Bede. I'm a developer from Melbourne in Australia. And I work on a content management platform called Simpler. So I'm here to talk to you a bit about web components for content management systems. So I've been working with CMSs for a while. And honestly, I've been a bit frustrated with them. Essentially, I've been frustrated both from a developer's point of view and also as a content editor I've been frustrated. A couple of years ago, though, I started using web components. And I realized these could potentially really change the way we look at content management. And they could help resolve some of these frustrations. So that's what I'm going to talk about today. I'm going to talk a bit about content management systems, where they have been in the past and where they are now, and how web components could potentially change them. I'm also then going to go over some of the patterns you might use to build out your own custom element for content management. So let's first look at a monolithic CMS. So a monolithic CMS is essentially your traditional CMS, such as a WordPress or a Drupal. It essentially gives you all of the functionality that you need in one single app. So on the one hand, this is great. It means it's really easy to set up and get going with. But like any monolithic system, it means it's quite rigid. So from a developer's perspective, it can be quite difficult, for example, to change the way you're displaying that content. For example, if you want to use a different framework or a different templating system, it's going to be really hard to wangle that in with the monolithic system. Also for a content editor, you're going to have a bit of frustration there. So most of these systems, you're going to have some kind of a dashboard where you log in and you edit that content in a form. The problem with this is that that content there is in a completely different context to what your user is going to see. It's a very different environment. So for your content editor, they're going to get a real disconnect between what they're seeing and what the user is going to be seeing. Over the last few years, though, there's been a huge, huge rise in popularity for something called the headless CMS. So the headless CMS essentially takes this monolithic system and gets rid of the view layer. Instead, it replaces it with generally a really consumable JSON API, or similar. Essentially, for developers, this is fantastic, because at this point, they don't actually have to deal with the CMS. Instead, what they're dealing with is just an API, so they can really use whatever framework or library or back end that they want to talk to that content. Generally, though, these systems are going to end up with a dashboard just like the monolithic systems, where you have to go into some form and edit that content in a different environment to your users viewing the content. So this is where components come in. What if we had a componentized model for content management? The idea here is that you essentially build upon a headless system with that API to consume content, except you take that view layer on the monolithic system and you break it down into really small chunks of data, such as image, text, or something a bit higher level like a blog post. So this is already being done on the dashboard of these other systems. If you go in, you'll edit a content type, so in a kind of componentized manner. But the idea here is that that view layer is embedded into the component itself when it's delivered to the user in the browser. On top of this, we're also adding in a editing layer that's embedded inside the component itself. So for our content editors, they're actually able to go in and edit that content in the exact same place and same environment that users are going to be viewing that content. Also, because this is a small, modular, and componentized system, we're trying to retain a level of flexibility for the developer so that they can still have control over this content and how it's displayed. So why am I talking about this now in the context of web components? So first of all, custom elements is the first time that we truly have interoperability. Before any componentized model was going to be restricted to the framework it was working in. This way, we can build components that can actually be distributed to any HTML environment. More than this, we also have encapsulation through Shadow DOM so that we can make sure that editing UI isn't having any side effects to the rest of the DOM. So what would this look like? So here, I've got a dynamic image custom element with a path property that maps to some URL somewhere. Essentially, it's just pointing to some data. I want, at some point, for it to fetch from an API. And I want to render out that content. So in this scenario, that means an image tag. Later on, I then want it to save back to that same endpoint. So we'll do a put request there. So this is for a developer. This is generally what we'll see. But what about that editing experience? So for example, here, we want the editor to be able to come in, interact with that image in an isolated environment, maybe upload a new one, manipulate it in some way, and then be able to escape, all in the context of that one image, and see what the user's going to see. So how would we build that? So I'm going to go through a basic primitive. I'm going to go through that dynamic image. And I'm going to focus on the fundamentals of the content part of that component. So I won't touch on the server. And I won't touch on the internals of that editing UI. So this means I'm going to look at, how do we store that content? How do we render it onto the page for the user? How do we toggle that editing UI to manipulate it? And obviously, how do we get and set that content over a network? So first of all, we need to create a basic dynamic image element. And that's inheriting from the base polymer element. And straight away, as early as possible, we want to set up an image on our instance that's going to act as a rendering point for all that data we're going to have. Next up, we want to append this into the light DOM in the connected callback. So we want to do this in the connected callback because only once the element is inserted into the DOM do we know that the user actually wants to start consuming this content. We also need to make sure that we're doing this into the light DOM, not the shadow DOM at this point. And that's because content should fundamentally still be accessible to the user. For example, if they want to use any third party style sheet or any third party library that expects an image tag to be on the screen, you need to be able to make sure that's accessible. This also opens up the door for really easy server-side rendering. So as long as your content is in the light DOM, anything that can spit out a HTML string can server-side render. So let's look at some properties here. Essentially, what we want is we want some properties that are going to be able to hold all of the content to display that image. So for us, that's pretty simple. That's just a source and an alt property. You could add some more meta information if you need, but this is fundamentally what we need. We also have a render function. So this is an observer for those two properties. So this is going to get called every time and just pass those props down to our image. This might be more complex in other scenarios, say if you're building an article element that's based on markdown. You might store the content in markdown so your render function is actually going to have to take that markdown and convert it into HTML. So at this point, we're storing some content. We're rendering it out to the DOM, which is great, but it's pretty basic. It's essentially just a wrapper for an image. It's not doing much. So let's look at adding in some editing controls. So on the right, I've got my template, which is how I want my shadow DOM to look for this dynamic image element. And essentially, we're encapsulating all the editing functionality into it. Now, you'll note my editor controls is surrounding the content, but really, that's just depending on the structure of your editing UI. It is important, though, it's beneficial for all of your editing functionality to be packaged into one element, just because this means that it's a clean separation of concerns, and it also is going to give you a performance benefit, which I'll talk about later. So first off, we need a way to make sure that we can toggle those controls open and closed. So we've just added an editing property to the host and an open property on our editor controls. And all this is doing is just making sure our host can control when they're open and closed. We also obviously need to pass down those properties and that data to our editor controls. And at this point, we don't really care what editor controls is doing under the hood. It might prompt the user for a file. It might bring up a canvas to manipulate it. But essentially, we're just giving it the data. And at some point in the future, we know we're going to want that changed data. Lastly, I want to look at a load controls method. So most of the time with a dynamic image, most people that use it, most people that come to your site with a dynamic image on it, are just going to be viewing the content. They don't actually want to edit it. So we don't want to burden them with the functionality that comes with the editor controls. So what we want to do is we want to have this observer function that when editing goes to true, we can then import a HTML file that has the definition of editor controls inside of it. And only at that point, once we know that the user definitely wants to edit, we can load in and pass and boot up the JavaScript needed for editing. You can actually do more than this. You'll notice this entire shadow DOM is only for editing. So you could actually defer all of your work for dealing with a shadow DOM until the user is actually editing content. So now we have a dynamic image. It can display some content for the user. And you can add an editing prop, which will open up some controls that you can start manipulating it. This is pretty simple. And it's a nice base to work on. We have an interactive and dynamic image element. But it's not there yet. We really need to have some kind of networking to be able to load and persist that data. So first up, you need some kind of property which is going to let you uniquely identify the data it's talking to. So I've chosen a path here to map to some kind of URL. But you could choose a unique idea, whatever essentially is going to pass you back to a unique URL. We're also going to need a deserialized function, essentially just a way to take whatever the server is giving to us and hydrate our own properties from that information. Again, this API is pretty simple. It's giving us nice those source and alt properties straight up. But in other scenarios, you might not have control over that API. So your deserialized function might have to do a little bit more work. Conversely, we're also going to need a serialized function, which is just going to do that same process in reverse. We just want to take the content stored. For us, that's our properties, package it into an object literal that can be sent over the wire later on. But obviously, we need some methods to actually perform these requests. So our load method is fetching a URL based on that path property. We're taking that JSON, passing it, and giving it over to our deserialized function. The same, again, pretty similar, just doing it in reverse. So we're getting that serialized function. We're calling it, turning it into a string, and sending it over to our API via a put method. So this save function, you're probably going to want to wire that up to some external UI. For example, a save button that you might have on a page, or perhaps an internal event such as those editor controls, maybe when they close, you want to automatically save. Lastly, we want to make sure that we're loading in that content at the appropriate time. So I'm doing this in the connected callback because, basically, you want to make sure that you're not making a network request too early, but you want to make sure they're getting it at the right time. So once the element is in the DOM, we're making that network request. But you could be a bit smarter than this. For example, you could use something like an intersection observer so that you could load in that content only once the element has been scrolled onto the page itself. So now we have a pretty simple image, but it can display content. It can provide an editing UI so that you can edit it in place and get feedback on that editing. And it can also dynamically fetch that content from a network endpoint and persist it back to that same endpoint. But this is just one component. Ultimately, to get to a CMS, you need more than this. You need a whole library of components. And that's what we've been doing with Simpler. So we've been developing out a bunch of primitive elements such as video or image and text and bringing them all together using other mechanisms such as authentication systems and global management systems that are able to synchronize save events amongst all of the elements and make sure they're all editable at the same time. But more than just a single CMS, wouldn't it be great if we had an ecosystem of these dynamic elements where people could mix and match and use the ones they need based on their website or app? And what if we could have a plugin system for those APIs so that you could choose the content source that you're using for a specific element? You could have multiple content sources on the one page. Ultimately, I think using all of these together and utilizing web components and the features that it gives us, I think we could really see a different approach and a better way to manipulate and use content on the web. So thanks very much. I hope this has been interesting. Please, if you're interested at all, come and chat to me afterwards. Thanks.