KYLE EINECKER:
So this is the orbiter's missing piece, json defined blocks. It has been quite the journey to get here because even before I got to the session, this had a bit of an identity crisis. Json defined blocks don't really make any sense anymore since I submitted the session. So this is now YAML defined blocks, but it's not YAML defined blocks because YAML sucks, so it's actually JavaScript defined blocks. (AUDIENCE LAUGHS) That's what we're going to be talking about. If you'd like to look ahead, if you're the type of person that likes to read the last page of a book first, my slides are at tinyurl.com/midcapcomponents and the code will be going through is at gitHub/ctrladel/midcamp2023. Alright and I am Kyle Einecker, your presenter. So a bit about me to start with. I'm a senior technical architect at a company called Proficient, on d.o I go by ControlAdel. I've been doing Drupal for about ten years now, a little bit under that. I live in Asheville, so when I'm not coding, I'm usually either hiking or drinking or both.
And I've recently moved to this keyboard, which is...
MAN:
Oh my gosh, why?
KYLE EINECKER:
It's ergonomic and it's auto linear and it looks cool. Most importantly, it looks cool.
MAN:
Good for him.
KYLE EINECKER:
No. And when I started typing, my speed went from this to that and I'm slowly on the way back up. It's been a long journey, that's over the course of about three months. It is quite the endeavor, but it's been a good way to fill my time up and to make a lot of funny typos on the way. So yeah, I've been going through that. No regrets really, it was frustrating at the beginning, it really made me appreciate the connection I had between my mind when I'm trying to get onto the screen and realize that I could take my fingers for granted and the muscle memory that they have. Like I said, I work for a company called Proficient or an 8000 person global digital consultancy. We do a little bit of everything, including Drupal, which is why I'm able to come here and speak today. They did assist with that a little bit. So yeah, I think we're always hiring, we always have a job for something depending on what you do. We do a lot of Microsoft, a lot of AWS, a lot of Oracle, a lot of Adobe Site core, Drupal, yeah, if you can think of it, probably have somebody doing it.
That's kind of where we're at at this point. And to the session. So layout builder blocks. The first thing to know about layout builder blocks, there's two different types of blocks you can place in Layout Builder. There are custom blocks and these are content blocks, essentially. These are content entities that you can place inside of Layout Builder, they have field label, they have view modes, they have four modes. They're essentially a type of content, much like nodes, that you can place inside of blocks. The downside is that they're like nodes, they're field able, they have four modes, they're structured, they're stored in the database, they're very rigid and just overall pretty annoying to work with when you're trying to build a component. And that's really what we're looking at today, right? Like when you're working in Layout Builder, you're working in a component interface and you're trying to place components. So you want a lot of flexibility both as a developer and an author.
And when we're talking about custom blocks, you lose a lot of that flexibility as a developer because it's all tracked and config, it's all stored in the database as a certain type. There's a lot of flexibility and a lot of composability with custom blocks. So if you can't tell, I'm not a fan of custom blocks for components and instead we should be using the other type of block that layout builder supports, which is inline blocks. And these are essentially programmatic blocks. So unlike custom blocks or content entities, inline blocks are defined programmatically in a PHP class. And that comes with its own set of drawbacks, because componentry is a front end task, right? Building components should be a front end developer test. But if you need a PHP class you need to be writing PHP. Well, suddenly you need to do quite a bit of back end Drupal to write a front end component. So inline blocks also have the benefit of using form API or field API. So you get a lot of that flexibility back of this is your data structure, these are the fields you're collecting a little bit closer attachment to the actual look and feel of the form that you're going to be authoring with.
The downside, of course, is that form API is old and has a lot of nuances and a lot of hidden areas, so it's really easy to either trap yourself into a hole or not be able to identify the correct way to get what you want done, done. And once again just requires a lot of Drupal knowledge and kind of a lot of that Drupal backend knowledge that front end developers may not necessarily have. And in my opinion, they shouldn't need to have to create a component. But it is better than field buildable content entities with custom blocks because we can work with these programmatically. We can kind of remove a lot of those roadblocks for front end developers with a little bit of custom code and a little bit of hope from our new core modules. So we're going to be talking about how to do inline blocks with JavaScript or defining them in JavaScript, today. But first, we need to kind of get all on the same page about what is a component and what is the purpose of a component. So we're not going to cover this for long, but we'll kind of just do a quick overview.
In my opinion, a component is something that stores content but not data. So if you ever need to surface this in a view, if it means anything besides just being displayed on the page, it doesn't belong inside of a component. If it's purely marketing content, purely page fluff, then it probably belongs inside of a component. So that's what source content from that data means to me. A component is a standalone modular UI element, so it should be able to place by itself and meet all of your brand guidelines, all of your site guidelines, whatever needs, it needs, it should look like it fits into the page. And then it's going to be reusable across many pages and content types, right? So it's not going to be a one off, it shouldn't be specific to one page, you should be able to take this component and really place it anywhere you want, even if it's only on two pages, right? But it should be possible and it shouldn't be locked down or hardcoded to a specific area of the site unless that is the requirement.
It can also be embedded into other components. So you should be able to take a component and you should be able to put that into another component and build a more complex component, right? That is atomic design. You go atom to molecules, et cetera, and you just keep building upon your foundation to create better and better and more complex components that are more powerful. And then each component itself is highly structured content. So that's something to recognize and be aware of. When you're talking about a component, it has a data structure, and if you get that data structure wrong and if you get that type, you're wrong, Twig is going to freak out and it's going to break your entire page. It's not just going to not render it. So even though it's flexible and it's standalone, you just need to recognize that internally it is still highly structured and you need to pay attention to what you're doing with that data structure or you're going to make some mistakes and that page might break.
And then we have an example of a pretty basic component here that somebody might make. So in my mind, that is what is a component. Hopefully we mostly all agree, if not agree with it for now so we can continue off the session. When we're also thinking about component, I think there's kind of six main areas that we need to really touch on as far as the different parts of a component and the different ways they need to be represented in any given component system. So when we're looking at the parts of a component, in my mind, the six are a template, the HTML structure, how do you define and get HTML onto the page? You're styling with CSS and JavaScript for any interactions or if you're doing styling through JavaScript or whatever you have there, your data structure, how is your data being stored? Where is it being stored? What structure is it being stored in? You need some way to collect your data, so the authoring form and then you typically need some amount of pre-processing or massaging to take the content that you've collected and then pass it to the template to render.
So you have a data data/render preprocessing layer as well. And we'll be coming back to this a little bit as we kind of talked through each part. But those are kind of the six key areas I think of when I'm thinking about components and how to build them in Drupal. The first question that we need to answer, does drupal have the concept of a component? And the answer is, right now, no, but it's coming soon, if you've been listening to my cursor at all this camp. So soon come in, Drupal 10.1 as a new experimental module is something called SDC or single directory components. And this kind of takes a lot of the concepts or some of the parts of the component we just talked about and really gives a definition to them in Drupal core, so that we can all agree upon it and we can stop redefining it over and over and over again. Because I don't know if you notice, but there's a lot of different ways people are doing components in Drupal and none of them quite agree with each other. They're all really close, they're all really similar, but none of them quite agree with each other.
So single directory components is a huge leap forward and that we're going to have kind of one definition for multiple parts of a component and be able to start building upon that instead of all doing our own thing. And looking a little closer at what single directory components actually does. So you place it either in your theme or your components, and then inside of the components directory in your theme or your module or whatever, you have a my component directory or whatever you want to call your component. And in there, you start seeing some of the stuff we were just talking about, some of the parts. You have your mycomponent.twig where your HTML goes, your mycomponent.yml, where your data structure definition goes along with a couple of other things. Your mycomponent.js for when the JavaScript gets associated with that component. Your mycomponent.CSS for any of the styling and then a couple of README thumbnails assets, miscellaneous stuff to make it easier to integrate the components into Drupal itself.
So this is the general data structure of a single directory components, I would say not the general data structure, the general structure of a component using single directory components. I would recommend definitely going to looking into it more Matteo and Mike have published a really good blog post about it, along with a couple other people. And as Mike was saying, there is some documentation on drupal.org now. Now, there's an experimental module and I'll follow along and give it a try. It's a really interesting concept and I think it's going to move us forward really quickly with getting componentry and getting contrib aligned on componentry in Drupal in a way we haven't seen before. If we look a little bit closer at the component.schema.yml. So probably, depending on what component system you are coming from this might be a new concept and it's kind of important to understand what it is doing. So in component.schema.yml what we're doing is we're explicitly defining the type and structure of the data so that the component knows what content should be passed and if that content is valid and it can reject it if it's not.
And it also informs developers who come after you, this is the data structure of the component and these are all the values and kind of what you need to be working in the template or working in the component, what's available and what's not available. So looking at it, you have your schema, which is a link out to a schema.json, and this defines all the different properties that are possible that you can define in a component. So if you're curious about what can be added and kind of what the intent of each one is, you can go to that git.drupalcode.org JSON file and read into it there. Then we have a name for our component so we can display it all nice and pretty. We have a status. So this is, I believe, experimental, stable, deprecated and one other that I've forgotten. But it allows you to say, this component isn't ready for prime time, this component is ready for prime time. This component we no longer use and react to it either in your system or just as a developer to know this is something I should be using or this is something I shouldn't be using.
And most importantly, we have the props key. So this is where you define the schema for your component and the structure for it. And this uses a spec called json Schema, which is widely adopted and generally used within the JavaScript ecosystem and community for this type of definition. And it's all based on explicitly defining the structure of a JSON object. So the first thing we have is type objects and that the props keyword is going to be a JSON object. And then from there we have a key called required, which says which properties are going to be required for this JSON object and which ones are optional if they're not listed. So from there we've got the properties and this is where you actually define all the different properties that you'll be collecting and all the different properties that will be available inside of your template itself. So, in this example, we have a primary, a secondary, and those are the only two. Obviously getting code on a slide is hard, so the right column here is actually supposed to just continue down on the left side.
But if we look at the primary property, we have a title for it, right? So we know what to call it and how to display it. We have a type for it, so it's a type array. And then we have items. And this defines what the type of the items that can be stored inside of this array. So in this case, it's just string. So primary will be an array of strings and then we can do something with that anyway knowing that we're only getting strings back. Secondary, on the other hand, is a boolean, right? It's just a yes and no, true, false and just has a title secondary. So the schemas and the definitions can get pretty complex. I find them generally pretty legible, but it is a bit verbose. So just something to be aware of. A long schema isn't necessarily intimidating or wrong, it just it's verbose to get all the different aspects that you need and if you have a lot of properties that can go on for a little bit. Moving on from properties, we have slots. So slots are a front end terminology and twig, we call them blocks, right?
It's just an area where you can stick to HTML and know where it's going to be and kind of understand how it's going to interact inside of the component. So, in single directory components, that's called slots, but that's just a synonym literally for a block and twig. And in this example, we have body. So you all know that the body of the component or the content of the component can be placed in there. And I believe it just accepts any random HTML. There's no data structure to it or anything like that, it'll just render whatever it's given. And then we have some Drupal things like library overrides. So you can attach libraries to these components if you have JavaScript dependencies or CSS dependencies or what have you. So you can bring those all into Drupal itself and you can also do your own JavaScript library definitions. By default, single directory components dynamically creates a library for the component that includes the .js file and the .CSS file. So that's all just automatic and wired up for you, you don't have to do that anymore.
But if you have a bigger, more complex JavaScript element, you might want to have a different set of libraries or create your own libraries for that component. So you can still do that and wire them up here.
MAN:
So question on that.
KYLE EINECKER:
Yeah.
MAN:
So just give (INAUDIBLE) chance to use case that you have like a sub template within your template or something like that. Do you need to define those dynamic dependencies here or they even exist or is it something that is just going to be by default you probably still have access to those styles, but it would be a little bit less descriptive?
KYLE EINECKER:
Yeah, so I didn't include it in the slides, but we can touch on it a little bit later. Single directory components introduces a new way to include templates and twig, and it's not really a new way, it's an alternative way to using the app namespace thing. So right now you can do like app module and then do a path to a template to include it. Single directory components introduces, you can do like an include, where is it? And then the ID of the component if I remember correctly, and that include in that pattern handles, including the JavaScript and the CSS at the twig layer itself. So, if you're including the component template at all in any other twig is going to inject the libraries and CSS for that component. Does that answer the question?
MAN:
It does. I guess also just with that, so, it would have to be rendering in that context for that dependency to be injected. If I wanted to make it explicit to say like for documentation for people to know, if you're looking at this independently, that it does depend on something else, would I be able to write it there? And within that trigger error.
KYLE EINECKER:
I'm not sure. I know Drupal is pretty smart about figuring out dependencies and not including them twice, so you'll probably be fine. But SEC is new, who knows?
MAN:
Maybe the (INAUDIBLE).
KYLE EINECKER:
Yeah, so that's an explanation of the schema.yml I just wanted to go through that since single directory components is such a new concept and I know not everybody has gotten a chance to dig into it yet. And we'll be building upon that as we go through the slides. And actually this is our first demo opportunity. So what I wanted to do is walk through a couple single directory components that I've created and defined. Let's see. So I've created some basic ones, right? Because we're going to try to build a simple molecule like a CTA banner. So I've created some of the foundational stuff that we'll need. And the first one here is going to be like our text component. So we have our schema, our machine name, our name, our status, and then the props. And here it's going to be real simple. This shouldn't be here, that was a mistake. So we have our type object and then we have our properties and this one's really simple. It's going to be an object type and because we're going to be passing it a field from Drupal like a WYSIWYG field, that field actually has two values to it.
It has a format and it has a value. So we're going to define both of them here in the schema and we'll pass both of them to the template later on and then we can render that formatted text and twig itself. And for the stuff that's collapsed, that looks kind of confusing, you're not quite sure what it is yet, we'll get to that later. It's all spoilers and it'll be explained. Alright, if we look at the template for that, it's really simple. So the properties are passed directly into the template at the top level. You don't have to go digging for them at all. So we have a text property here that is an object. It has two properties, a format and a value. And if we go into Twig, we are creating a variable that says processed text equals this render array of process text. The text value for that is text.value and text.format. Super straightforward, super simple, and then we render that variable and that gets us our formatted text from WYSIWYG. Looking at, say, an icon component. This one, not a huge fan, I probably wouldn't do this on a production site, but for a demo it's fine.
We have a schema, we have a dependency. So I'm using a web component library called Spectrum that Adobe publishes just as a way to get some stuff onto the page that looks decently styled and has some options that come from a real life system instead of just all being demos. So we have a dependency on json_block/spectrum, which is the library that defines that and includes it on the page. We have our props, again. We have an icon property to select from a list of options, which is called an enum in JSON schema. And then we have a size of small, medium, large, extra large, simple enough. And I guess, question, is the text dig enough? Can everybody read this? Awesome. Alright, and then if you look at the twig for that, this is why I wouldn't do this on a production site, but we're just kind of doing a little bit. And if statement to get the SVGs and put them into a variable. And down here we compare the icon value to the string to get the SVG and then pass it on to our web component, passing our size and giving it a default value if it's not provided for some reason.
And then we have our SVG that we're including. So simple enough icon looking at a heading component and the great big world of component systems. I found that a heading is never just a heading, it is an element type, it is a style type and it is the text that actually goes into it. And sometimes it's multiple lines of text that goes into it and not just one. So that's where single directory components really excels, because we can say a heading is a simple concept, but there's a couple of different properties that are really actually part of that simple concept that we need to account for and be ready for it all given times, regardless of where we're using a heading. So, in that sense, we have our text, which will just be what's displayed on the page. We have an element div through h6 and then we have a style div through h6, simple enough. And with heading, we don't have any fancy web components or anything, we're just taking the element value and making it the tag because that is what it's defined as.
We have a class for the style and we pass the text in. Once again, you'll notice that these components are really simple, they're really straightforward and that's awesome. There's not a lot of complexity going on here and anybody can come in and read these and understand what's going on. Now the button is where things get a bit bigger and a bit more complex. So this is a button from the Spectrum library and it has a lot of values that are useful in the right situations, but you might not need them in every situation, but they're still here because they're part of the component and part of the functionality of the button that's being defined. So we have an active acquired a treatment which is an option for fill our outline. We have the type of button, whether it's a button, a submit, a reset would have you, the label buttons aren't usually buttons, they're links, right? Ops, spoilers, we'll get to that later, So the link has a URL the entity is referencing an entity, and the title to actually display a size, a variant and an icon.
So the button includes the icon definition. You'll notice that this makes it very verbose because the icon definition is now repeated in two places and we will get to why that's a bad thing and how we should address it later. But for now, just note that the icon definition is now repeated in two places, which is not great. And then we have the icon properties. And in the twig, we have a lot of values going on now, but this is still pretty straightforward, right? We're just taking the values we're collecting and we're passing them through to the appropriate properties, attributes and parts of each web component or each element. And this is what I was getting at by the new include statement. So it says json_blocks:icon here and that will include the SDC component for Icon along with any of its dependencies and JavaScript, CSS, what have you. And we're passing only the icon property to it so that we're not polluting it with the context of this component as well. So yeah, those are basic components.
We'll be going into a bit more detail later about how to integrate them into Drupal and how to really collect data for them. But for now that's our baseline. Oh and then we'll be creating a CTA banner component. I think I can jump on to the other one for this. So for the CTA banner component, we're going to start pretty simple. And we're just going to collect a property of background, right? So we want to be able to give our banner, our background color. So right now that's all we have for our CTA banner. Alright, back to the presentation.
MAN:
Got question.
KYLE EINECKER:
Yeah.
MAN:
If you have (INAUDIBLE) link and (INAUDIBLE), what are those?
KYLE EINECKER:
So those are coming from the Spectrum Web component library. Yeah. So, I guess I was also using preparation for this presentation as a way to see if I could integrate web components into single directory components. And the answer is I can. Getting single directory components to layout builder. So with single directory components, there's not really anything baked in for integrating it into Drupal outside of the render layer. You have the ability to define a render array, you have the ability to include the template into Twig, but there's no representation, like there's no entity type for a single directory component, there's no block type, there's no representation in the interface in any way or anywhere of a single directory component. So the first thing we need to do to start using (INAUDIBLE) components and layout builder is get them into layout builder. And if you're not familiar with the plugin system in Drupal, it has this concept of deriving a plugin. So what we can do is we can take a list of all the components available inside of all the SEC components available to Drupal and create a block for them, block for all of them.
And we can do that programmatically and repeatable without having to define each one independently. So if we jump back to the code a little bit, what that looks like, and I fully expect at some point there will be a contrib module that does this for us, but I think it's going to take a while for us to agree upon what the block is going to be in, how it's going to function. So I expect to see a couple of different variations of this manifest itself until we all agree about what it's going to be in with the shape it should take. But for this demo purpose, you can see it's still called JSON block here because I started on some stuff and I didn't rename any of it, but just imagine it says JS block or something else that is more appropriate. So we have our block definition. This is pretty straightforward. An ID, an admin label, a category, and then we have the deriver. This is what it says to Drupal. This block is not just one block, it is a bunch of blocks, and when you call this class, create a bunch of these blocks and use this JSON block class as the way to render and process all of them.
And if we keep going through this block, there's really nothing too complex about it. It has a configuration, it has a build method. You can see we're building the render array for the component here where it says, type component, and then we pass the component ID from the plugin definition and we pass to the props key, we pass the values and if we had any slots, we would pass slots as well. We return that so Drupal can render out the components, then we get to our block form. Spoilers, we'll get to that later. And a block submit. If we take a look at the the deriver or the derivative class, this is actually really straightforward and really easy. All we're doing is we're calling the STC component manager and saying, get all components. And then for each component in the list, get the definition and create a new definition for that component as a block. We pass it kind of the base plug-in definition because there's little bit of magic that goes on to derive blocks. We give it an admin label and we give it the definition for the component and that is how they're all created in Drupal.
And if we go over to Drupal, I do have a demo and this is going to be a live demo, so we'll see how smoothly it goes. I click Add Block. There we go. So we have our SDC blocks here, we have our button, our CTA banner, our heading, our icon, our image our text, but there is a bit of a problem. If we click button and I'm in the right state, we don't have any fields. We can't author anything we can add to the page. Can we add it to the page? We can. Yeah, that's not great, is it? So it's the first step, though, right? Our components are in layout builde, we can place them on the page. Good stuff. Going back to the presentation. We did the demo, so now we have a bunch of individual components, but we need to build a system of components. And that means we need to build components on top of components and we need them to be related and they all need to make sense with each other. But there's a bit of a problem, if we think about back to the parts of a component, our template or CSS or JavaScript or data structure, etcetera.
There's kind of really two key criteria we need to evaluate these on, and we've been evaluating them on the definition of the approach, right? Do we know how to do a template? Do we know how to do CSS? Do we know how to do JavaScript? Do we know how we're doing our data structure? So we've been doing the definition of it, but we haven't been evaluating it on the composability of those parts. So if we look at it like, this is the CTA banner and we're going to make it contains a heading, it contains text, it contains background, and it contains a button, and it also contains the icon inside the button. So how do we get all of that componentry into one place to create the singular component? And how do we do it in a way that developers are friendly to authors, and a good experience because you could just say, alright, author, just put all five components on the page and that's it. You have to do that for every component, but that'd be terrible. So with that in mind, we're going to look at the two criteria we're evaluating, which is the approach defined.
And we'll just call that D. And then is the approach composable, which we'll call C, and that will make sense here once I go to the next slide. So when we're looking at the parts of a component, when we're looking at the template, is it defined? Yes, we're using Twig, easy enough. Is it composable? Yes, Twig has embed include extend. We can take one component and put it into another component really easy when we're looking at CSS. Is it defined? Yes, we have Drupal library system. We have the CSS in the component directory that is defined. Is a composable? Yes. Drupal library system can include libraries and dependencies and resolve all of itself. So we're good there. Same for JavaScript. We're using Drupal library system so that is both defined and composable. But then we start running into a problem. We have our data structure, we have a definition for it, but as we saw, it's not composable, right? We had the icon definition duplicated in two places. So that's kind of where we're at with SEC ends right now.
We have the basics of a component, the foundation of it all figured out. But how we take that and we build a system on top of it and how we create authoring forms and how we do pre-processing of that is kind of up in the air and to be decided. So our data structure is not composable, our authoring form not defined at all, there's no approach for that defined, so certainly not composable either. And same with data and render pre-processing, there's just no approach where its defined and there's no composability to it. We'll be stepping through data structure and authoring form. I ran into problems with pre-processing. As it turns out, Drupal 10 is a little bit different than Drupal 9, in some regards when you're integrating SDC, it also makes it a bit messier Anyways, onto data structure. When we're looking at composability of the data structure, what we're really looking for is to be able to bring the data structure of one component into another component, right? We want to say this is our atom, we're building a molecule, we need these two atoms to make the molecule.
We just want to bring in the data structure for those two atoms. We don't want to redefine them every time. We also need to be able to override all the aspects of the structures we're bringing in, right? So the default values, the options, the displayed fields, basically, we need to be able to create a new form view mode for those data structures if we want to. Sure, we can take all of it as is, but if we're having a button and we know the button is always going to be a primary button, we know it's always going to be large, should we display those fields or we should just give them a default value and hide them so the author can't change them? So stuff like that. And then we also need to be able to define new properties alongside composed ones, because our CTA banner, it has a background and that is a property of the CTA banner component is not a property of an atom. So alongside our compose properties, there needs to be standalone properties for the component itself. And this is where JavaScript comes in.
So we were looking at YAML schemas, but all of our front end tooling already has a build process in front of it, right? We build our JavaScript, we build our CSS with SASS, so why don't we just build our component definition files too, right? So instead of a YAML file, what I've been doing is I've been creating JavaScript files for my definitions and been running them through a webpack build process to turn them into YAML files. So if we look at button here. We'll bring some stuff that we haven't gotten to yet. It's really simple. We have our our export of a JSON object. It's the same structure just written as JSON instead of YAML. Let's see, I'll minimize a bunch of stuff. When we want to include the icon. We don't have to retype it. We can just import that definition from the icon definition itself and reuse it here. So that's what we've done here. We have our icon components and it's just including the props value from that definition here. And then when we build it, it'll all be one giant file, which is what SDC needs.
So this is, I think, really the heart of the talk, which is, let's start building our definition files instead of just manually typing them all out. And there's a lot of benefits to this because we are able to bring in and compose our definition and our data structures, which is great. And then we get a bunch of tooling with it too. So if I want to go to this definition, I can just do Ctrl B and my ID will take me to it. I don't know what the shortcut is for all of your various laptops and IDs, but it should be possible. And that really helps with the developer experience, right? Because this doesn't really tell me what this is at all, it tells me it's an icon component that's bringing the props. But what are those props? If I want to know as a developer, I want to be able to navigate to it easily. It also gives us a huge benefit in that we can do any type of preprocessing or any type of manipulation of that data structure that we want. So I believe I have this here somewhere, right? What we could do in our CTA banner component is we could import the button component like we're doing here and we can destructure it into a variable and we can change the properties that the default values as we want for our CTA banner only and then just pass it along like we were doing before.
And you'll notice here that... This is the wrong one, there we go. Yeah, so we had our background property for CTA banner before, but now we also have a heading, a text and a CTA, and this is really easy to read, right? We're just importing our atoms and using the props for each one at each layer where relevant. And for CTA props, obviously, we're doing the pre-processing before we're setting it, but this gives you a lot of flexibility and a lot of power to really do whatever you want in the JavaScript world and then ultimately just spit out a YAML file that SDC ingests into Drupal. Let's see if I've forgotten any talking points. Oh, right, so the other benefit we get is that if we're trying to autocomplete things, it becomes really easy. I happen to have an image one defined that we're not using. And if we go to image component, the autocomplete for me and we can do props, so real easy to add an additional component to your data structure that way. And like I said, all this code is available on GitHub because what really makes this possible is this Webpack plugin that I sourced from somewhere.
I think I sourced it from Chatgpt and modified it a little bit to get working how I wanted. But all it does is it looks for a pattern in my Webpack definition file, right? Components .js and processes them one by one and spits them out as YAML files. And if we run that process right now, we can see we're processing each one, and if we go back to our components directory, we've now got a component.yml for each component, which is great. Which means I can also now delete this components_yml folder because we're no longer needing it. See, is there anything else to touch on with that?
WOMAN:
So, I guess, you typically going to ignored those...
KYLE EINECKER:
Yeah, because you're running your build process. Well, it really depends how you're distributing it, right? So this is a module. If we were distributing the module, we would ignore them during development, and then as we publish the module, they would be able to process to commit them to like Drupal.org or something. And then it'd be the same for a theme if you're just kind of working at the site level.
MAN:
Do we have to use webpack now? (INAUDIBLE)
KYLE EINECKER:
You can use anything you want. JavaScript has lots of options.
MAN:
We were using yeet (LAUGHS)
KYLE EINECKER:
The first use case for yeet. Alright, so, going to JavaScript for our definition files and running a build process, it gets us that composability that we need for our data structure. We defined the components of JavaScript files, we import them to each other as needed and we build HTML and we're good. We're good to go. Next up is authoring form. So this is a bit more of a mess. We want to take the schema that we have, right? We have a great definition, a highly structured definition of what is a component and what values it will accept. And we now need to collect that from an author somehow and we need to pass that to the component so that we can render it. But it makes a lot of sense for us to want to generate that form based on the schema. And we should be able to but there's an important distinction that you need to recognize, which is that the authoring experience is not just a data entry experience, right? You want to make it clean, you want to make it easy, you want to make it fast so that your authors don't hate you.
So there is a little bit of that that you need to be aware of when you're creating this experience. One of the other goals is that defining this authoring form should require as little Drupal knowledge as possible. If you have to have a bunch of Drupal knowledge of mapping field types to JSON schema data structures, that's a bit of a pain and a barrier to entry for front end developers who might be really good at building a component but know nothing about Drupal. And then as we're talking about experience, the goal is for it to be at parity or better than what's available, at least in Drupal core, right? We don't want to have any regressions or have any kind of weird experiences that make life harder. So at a minimum, we need things like media library, we need entity autocomplete, we need whizzy wigs, we need the basics to get the content onto the page. And it needs to be easy and approachable to extend because one thing you can't say about field API and form API is you can write as many different field and form widgets and types as you want.
So whatever we choose here, we need to be able to do that as well with our SDC components. And, jumping ahead. So there's kind of two ways you can take this. If you're familiar with the component module, it just lets you pretty much define your form API render array in the definition file, and it passes that pretty much directly to your block form and that's a fine approach, if you have a team that knows form API and is comfortable working on it. Great, go with that. You're going to have all the power of Drupal form API at your hands and that's nothing to sneeze at. But if you're working with a team that knows less Drupal or doesn't really want to learn from API, then I've found that it's useful to use a library called React JSON schema form and it handles taking a JSON schema and turning it into a form. Actually, I believe I have it open. Yeah, so this is the demo page for react JSON schema form. Up here we have a bunch of examples, a couple of settings that we can toggle on and off, and then really the meat of it is this.
So we have our JSON schema definition and this is the same spec, same compliance, same structure as what we're using in our props, key, and single directory components. But additionally to that it has UI schema. So this is kind of where you get control of the look and feel of your form. And can start improving the authoring experience, changing the field widget, the field types based on the type of content you're collecting. And then also in this demo they spit out the form data, so as you're authoring, it'll update the content here. And we have an example form here, right? So this is a pretty simple schema that has a first name, last name, and a telephone. With the default, Chuck Norris. Yeah, and as we change things here, let's go Chuck Kyle. We can see it types in down here and there's a bunch of them. So JSON schema obviously has objects, it has arrays, it has multi-value fields and react JSON schema form has pretty much full support for JSON schema as far as I know. There's probably some edge cases you can get in some weird situations with your schema definitions, but if we take like a nested look, you can create a multi-value for field thing and move it up and down with this arrow.
In general, this playground is going to be worth looking at if you're looking into the React JSON schema form library. And I've written in a module as well that integrates into Drupal form API, so you can create a form element with RJSF, pass the UI schema and then render it into Drupal itself. And that is what we're going to be looking at with this demo. So some of the stuff I was hiding earlier. Let's choose a simple one. So heading component, third party settings. So this is a key in SDC that allows you to kind of shove whatever you want into it. They do ask that you namespace the top property with the module that you're using. So in this case we're using the RJSF module. So we're in the RJSF area of third-party settings and we're going to define our UI schema here because we can't just include it alongside the schema down here inprops because that would violate the props data structure and not be the correct way to do it. So for heading, heading is three fields, right? It's a select list for element, a select this for style and an input field for what you're displaying.
So we don't actually have any UI scheme at all. We don't need to change any of that, if we get to select lists in an input box we're good. All we really need to do is give it a title. And so that's why I've done here, I've said UI title heading and I'll display. If we go back to our JSON block, I'm going to uncomment some things. So this is all the code that handles creating the element with form API. You can see it's actually very straightforward. We get the configuration for the plugin that we were deriving, we create a schema object to pass it along to the form state as a component. If I can get that to go away. And then we create our element with type rjsf_editor schema, UI schema and the default values so that it can render correctly. And with that, I believe I've commented out. Oh, yeah, that is broken. Alright, so with that, if I clear the cache, we should end our Drupal site now. I want to go to add a block and add a heading. There we go, we have a form. There is no Drupal code specific to the heading that is generating that, we're just taking all the definitions in our SDC and creating a block with the form for that.
And we can say, Kyle's heading, we can give it an element of h1, style of h1, add it on, and there we go, we've got the rendered heading tag on the page with no Drupal code at all really. No specific code for heading, just all wired up with magic. And as we get to other forms, it can obviously get a lot more complex. So looking at (INAUDIBLE) so all of the JavaScript files here have the definitions already in place for the, let's see, they all have the definitions in place for the form. So looking at this full one that I prepared beforehand, I'm going to copy it over and we can see in the third-party settings for the banner here, we have UI schema, we have the background, which that's a unique color picker attribute, or widget for the background. And then we're just doing the same import thing as we were doing before for the third-party settings where we're just grabbing it for each component and placing it into the right place in this definition file. So we should be able to just copy this over to here.
And I guess before we do that, we'll go to add it to the page right now. Yeah, so right now we just have a background color, that's obviously not everything we need. We do a build, we do a CR, and obviously you could make this a watch during a normal site build. But for demo purposes, I want to control when things we're building, and now we go and add our CTA banner. There we go. So now we have this great big form that allows us to author everything we need to author. That's not great, there we go, that's better. Alright, so we have our background color. Let's go with green for now. We're going to put our heading value in, give it an element and a style. We're going to move on to our text element, grab some Lorem ipsum, put that in, and you can see here, so this is actually a Drupal version of the WYSIWYG. It is controlled through the normal formatters and filters that you configure in Drupal itself and just renders the editor and mounts it through normal Drupal JavaScript processes. Which is why we also have the text format of basic and full HTML.
And we can indeed do things like bold text and whatever else you want to do With that. We have our button and this will do an autocomplete, but this autocomplete is not working right now, but it does pull in content that is available. Well, sorry, the auto complete is working, we can store data just fine, rendering is not working right now because that requires a little bit of preprocessing and data manipulation that I do not have working. So we'll just drupal.org, I'll say click me because it's CTA button and we have a bunch of different button properties with a little bit more time we could go through and hide these as needed. So the form was shorter, but for now we'll just leave them and then we can choose an icon. Let's go with check mark and then click add block and there we go, we got our component outage without really anything specific to that CTA banner component, just kind of wiring it all together. Let's see. Yeah, so, react JSON schema form is a cool little module I've written and like I said, it really makes it possible to take SDC and fully integrate it into Drupal itself at kind of a component system level instead of a component by component level.
And, render pre-processing still not done. React JSON schema form does have a definition and approach for it and it is composable but it's not working quite right now. Also, RJSF isn't working with Drupal 10, I need to go fix some things. So unfortunately you won't be able to take my module and get it working with 10.1 right now, but hopefully after tomorrow you will be able to. Yeah, I found a couple of bugs I need to address there. Trying to see if there's anything else to address in the code demo. I don't think so. Yeah, I believe that's everything. RJSF does also come with entity browser integration, so when you click image here we have a multiple media reference field just as an example, we can click add media and this will pop up a window that uses entity browser. So you can select some images, we'll select three here, and it just pops them in down here. And this is where I was saying in some ways it's a lot easier to do things better than Drupal core because we're able to use react libraries to just drag and drag things around and you get nice little sliding animations.
Yeah, it's so simple, right? And then we click add block and we get our images rendered in here. So I believe that's everything. There was also the color picker we saw earlier that's unique to RJSF, the module as well. So that's a nifty little custom, something that we wrote. Yeah, let's see. That is everything. Any questions?
MAN:
Well, I was going to ask if you had media integration, but you just...(LAUGHS)
KYLE EINECKER:
Yeah.
MAN:
So are you fully building your (INAUDBLE)?
KYLE EINECKER:
Our component systems, like the back end?
MAN:
Yeah, your content like...
KYLE EINECKER:
We don't have a lot of content types anymore. So the question was, are we fully building our back end with this? And for the sites where we use this one, we don't have a lot of content types. We only have content types for structured pages, but we generally have just one layout builder content type that's just the whole page layout builder, yeah.
MAN:
(INAUDIBLE) a molecule, we'll say, and I want to control some of that stuff inside. Is it impossible from a molecular level or how does that (INAUDIBLE).
KYLE EINECKER:
Control what type of stuff inside?
MAN:
Say, I want to control the body, but I have a header, I want to control the color from the molecules. Is that a possibility?
KYLE EINECKER:
Yeah, you just have to think your schema is an interface, right? So as long as you're rendering layers, passing something that matches the interface back, it's going to render correctly. So you obviously can't introduce like a new button type in the heading and try to render it as a button, but you could add to the button definition then, yeah.
MAN:
OK
WOMAN:
So this is a custom solution, right? This is something that can be used as a contrib module or built into the new component module.
KYLE EINECKER:
All the code we've seen right now, yeah, that's custom. Our RJSF is a contrib module. You can add that to your site with composer require, but the deriver and wiring everything together that's custom right now. I mean give me a break, it only landed in 10 last week. (AUDIENCE LAUGH)
WOMAN:
We're not just saying it for conversations about wanting to implement this and so you might want to join this conversations if you're interested.
KYLE EINECKER:
Yeah, I've been talking with Mike and Mateo about it. I expect that the form generation part of this will be one where we have multiple competing solutions for a while because they all have their benefits and drawbacks, and there's a couple different ways to do it. I know some people want to do it in PHP instead of JavaScript but I think it's a lot easier to write nice form elements in JavaScript than it is PHP. So, any other questions?
MAN:
Are you running this on a (INAUDIBLE)?
KYLE EINECKER:
Yeah, this is running 10.1 right now.
MAN:
OK. Good question. Are you using JavaScript? But it seems like you're strongly typing all of your stuff. Why are you using Javascript? is that like extra...
KYLE EINECKER:
Effort, right now? That's a demo. Yeah, I mean, once you have your definition files in JavaScript, you could go as crazy as you want with TypeScript and typing all of that and connecting it all together. But you don't have to you can just do it all in JavaScript and essentially be doing it by hand. Yeah, it's certainly possible that you could integrate TypeScript and have strongly typed definition files.
MAN:
Can you show us one of these final photos of the (INAUDIBLE).
KYLE EINECKER:
Yeah, so if we go here. So we have our schema machine name, third party settings, so this will have them expanded, we have our background, heading, text, CTA, CTA I called the button, I just didn't name it, but I call it CTA because it's a bit more contextually correct. And then we have our props once again, we have our background, the headings. Yeah, so you can see it's literally just taking that definition and spitting it out into the YAML file. Let me just continue on and on and on, yeah. Any other questions?
MAN:
For building the schema, is there going to be documentation or example code or things just to help get started? Like at least the most basic of components.
KYLE EINECKER:
Are you saying, like, for single directory components, are there examples of writing the schema YAML?
MAN:
Yeah, like in one of your first code examples.
KYLE EINECKER:
Yeah, so this is the way to get access to everything because this is what the schema is validated against. That's really small. So this will give you need as far as everything that's possible inside the schema itself. And then, let's see, I believe there's an example of the component.yml file for single directory components right now on drupal.org, so that'll explain everything that's going on in that file. Any other questions? Alright, then. Thank you very much for coming to the talk.