In this tutorial, we're going to learn how to create custom element settings for the Page Builder app. Although the app comes with a bunch of ready-made element settings plugins, at one point in time, you might need to create your own to satisfy your specific requirements. To achieve that, we can utilize a simple plugin, which is what we'll cover in this short tutorial.
If you are not already familiar with how plugins work, we recommend you first take a look at the Plugins Crash Course before reading this article.
All of the code shown in this tutorial is also hosted in our GitHub repository.
Ready? Let's dive in!
What we'll build
We’ll create a new page element settings plugin, which will allow a user of the page builder app to add CSS classes to any page element.
Here's what the result will look like:
Under the hood, every page element is a React component. Therefore, the value of the
CSS class will translates to
className prop on component level.
settings.className property of an element is special because the rendering of this property is already handled for you.
How is it handled, you ask?
Well, every page element is wrapped with the ElementRoot component. Among other things, it is also responsible for extracting the
className value from the
element.data and and passing it to the element for rendering.
1. A Webiny Project
This tutorial assumes you have already created a new Webiny project to work on. We recommend going to our quick start guide which will show you how to do it.
2. Project structure
We'll add the code for our plugin in the
apps/admin/src/plugins/cssClass folder and we'll pass it to the app later on.
You can place the code for plugins anywhere inside
src folder. For convenience, I like to group all plugins under a single folder named
The project structure of our
admin app will look similar to this:
In order to work, the plugin(s) defined in the
apps/admin/src/plugins/index.ts will need to be imported and registered in the
admin/src/App.tsx as shown below.
Creating the Plugin
All of the settings available for a page element can be accessed via the top app bar, which appear as soon as you select a page element in the editor:
As mentioned, this list of element settings can be expanded and custom element settings can be created via plugins. To create a new page element setting, we only need to register a single plugin, that will define three things for us:
- How it's rendered in the top action menu of the page editor?
- What settings that plugin will apply to the page element?
- And which page elements can use this setting?
Defining the Plugin
Let's add the new page element setting in the editor.
First, we'll create/define the necessary plugin in the
This plugin will of
Before we cover what's inside of Action and Settings components, let's first understand what each property means in the plugin we just created.
nameproperty holds a special meaning here. Unlike other plugins, the name property is required here because it will be use to assign element settings to a page element using
renderMenuare the two key properties of this plugin. They define how the settings action and settings menu will be rendered in the editor, respectively.
elementsproperty holds either a list of page elements for which this setting will be available or a boolean value of true which enables the setting on every page element.
elementsproperty can be set to one of these two things:
either a list of page element types for which this setting will be available. For example,elements: ["text", "column"]
or a boolean value of true which enables the setting on every page element. As shown in the above example.
renderAction property of
pb-editor-page-element-settings plugin is a function that renders the settings action in the top editor toolbar.
If we look at the implementation of
renderAction in case of our
"pb-editor-page-element-settings-css-class" plugin, it just returns a Action component.
Now, let's take a look at this Action component. Tt is a simple React component which is responsible of mainly two things:
- Rendering of the tooltip and icon for the settings action, which are passed as props to it.
- For opening and closing of the actual settings menu for the very plugin provided as prop.
Checkout the full source code of Action component in our GitHub repo.
renderMenu property of
pb-editor-page-element-settings plugin is a function that renders the settings menu, which will get rendered when the action icon is clicked.
If we look at the implementation of
renderMenu in case of our
"pb-editor-page-element-settings-css-class" plugin, it just returns a Settings component, which we'll implement in a moment.
That's a lot of words to process. Let's take moment to briefly look away from the computer screen for a minute or two to a more distant scene or maybe brew a cup of coffee. Alright...
Now, let's implement the Settings component. The goal for this component is to render the menu for the actual setting, which generally involves a Form so that the user can edit the settings. We'll go through the implementation step by step. We'll start by adding the boilerplate code and then move to the actual business logic.
Let's create a simple form that will render a tab containing a label and input box.
With the above code we'll be able to get a menu as shown in the image below:
Of course nothing will happen if you try adding input value because the actual business logic for saving the
className value is missing.
So, let's add it.
First, we are going to import
updateElementaction creator and
getActiveElementselector to update the page element data and get active page element, respectively.
Then, we'll fill in the code for
mapDispatchToPropsso that we can use active
Now that we have the active page element and a helper to get active element's data, let's implement the actual business logic.
element.data contains the information about various attributes of a page element. One of the attributes is
settings, which managed by various element settings plugins.
Our goal is to edit and store
className key-value to this very object i.e
First, we're going to extract the
settingsproperty from element's data object and attach
classNamekey to it.
Then, we need to implement a
onChangehandler for the form so that the
classNamevalue can be update using the input field. For that, we'll import
useHandlerhook that will help us to implement
With these changes in place, our CSS class plugin will allow us to add a class name to every page element.
We've successfully created a simple element settings plugin, which can be use to add
CSS class to every page element in our Page Builder app.
Plugins are one of the core features of Webiny. The whole Webiny architecture is based on it. The plugin system is very simple, yet powerful, and allows you to easily add new functionality.
Are you interested in building your own plugin? You can easily add custom elements following the plugin crash course.