Custom Modules
Introduction
With custom modules it is possible for an agency or developer to create a personalized module intended to extend the functionality of our Editor. This custom module will be fully integrated into the Editor Page Builder and will be available as another core module. It will thus be possible to create a complete custom DOM structure with custom styling and even custom JavaScript.
Custom modules are defined on a front level and not at organization level. This is important to consider when planning the roll out of a custom module for a customer/organization with multiple fronts.
Setting up a custom module
Custom modules are set in the front configuration tab of a front, in the Organization Manager and by users with an admin or agency role.
A single front can contain an unlimited number of Custom Modules. In the picture above you can see that each definition is a row in the customModules
array.
Each Custom Module requires the following information:
| This is the so-called “slug” of the module. It will be used as a reference when a module is stored in the Styla DB. Therefore, it needs to be a unique identifier (cannot be the same as another module for the same front) and cannot contain spaces or special characters. The slug is case-insensitive, and will anyway be converted to all uppercase by our system. We will also automatically prepend your front name followed by a dot. |
| This is what will be shown in the Editor UI, e.g. when dragging and dropping a new module. This can be a descriptive name and can contain spaces. E.g. Countdown Module |
| A URL pointing to a JSON file containing the custom module’s data structure definition (*). |
| A URL to a handlebars template file that will be used for rendering the DOM structure of the module (*). |
| OPTIONAL A URL pointing to a javascript file that would be executed in order to extend the functionality of the module or enrich it with a dynamic behaviour. |
Let’s look in more detail at the schema
, template
and js
.
Schema (Data structure)
The edit schema file contains the definition of the dynamic data of the module and the corresponding UI for editing it in the module edit panel.
In order to define which fields will be available (with a related fields definition) we use the React JSON Schema Form specification (https://github.com/rjsf-team/react-jsonschema-form ).
Since the Editor UI provides different tabs for managing content, we support 2 main blocks as children of editSchema:
| This is what will be rendered in the content tab. Here is where you define the fields that will be used by the content manager to create content (e.g. headlines or paragraph text) | required |
| This is what will be rendered in the settings tab. Fields like “number of products per view” or “module padding” usually belong in this tab | OPTIONAL |
Each of these blocks (content
and settings
) support the following fields as children:
| This is the data definition. Here you will define what the fields are called, what type of field they are, what their default values are, etc. | required |
| This is the UI definition. For each data element defined in the data block you will be able to specify which UI element should be used for rendering. | OPTIONAL |
Example
If we want to create a very simple module where we can add a headline and then have a slider control to set the font-size, we can write it like this:
{
"content": {
"data": {
"properties": {
"headerTitle": {
"title": "Title",
"placeholder": "Enter title here",
"type": "string"
}
},
"type": "object"
}
},
"settings": {
"data": {
"properties": {
"fontSize": {
"title": "Font size",
"type": "number",
"default": 12,
"minimum": 9,
"maximum": 24
}
}
},
"ui": {
"fontSize": {
"ui:field": "SliderField",
"ui:options": {
"marks": {
"9": "9",
"12": "12",
"14": "14",
"20": "20",
"24": "24"
},
"step": 1
}
}
}
}
}
As you can see we don’t have a UI block for headerTitle
, inside the content object. This is because we just want to render a standard text input, so there’s no need to declare a specific UI element for it. We do that with fontSize
, however, since we want to use SliderField
and also specify which steps are allowed. default
, maximum
and minimum
, on the other hand, are defined in the data part.
SliderField
is one of the UI widgets provided by Styla. Here is the full list:
UI field name | Description | Data Type |
---|---|---|
| Shows a draggable slider for selecting a number value inside a given range. Supports a “step” parameter and only allowing a specific set of values as well. | number |
| Shows the enriched link field, with support for selection of internal vs. external and the style selection dropdown | Object {
link: string,
text: string,
stylePreset: string
}
|
| Shows the Rich Text Editor field. | Object, using the Quill delta specifications: https://quilljs.com/docs/delta/
This also requires a UI config for specifying which elements are going to be shown in the Toolbar. More details on this in RichTextField Options |
| Image Uploader | Object {
url: string,
width: number,
height: number
}
|
| A regular input field. As mentioned before, will be used as default for strings so it’s not necessary to explicitly set it | string |
| A multi-item widget built for menu entries. It allows adding, deleting and sorting. It also supports nested items, by dragging items on top of the others. For each entry it stores a title and a link. | string
NOTE: this is a UI widget, so it needs to be used with the following syntax: |
RichTextField Options
The toolbar of RichTextField widget can be customized based on the specific needs. It’s important that a UI config is provided, otherwise no options are going to be shown.
This is a recap of the allowed toolbar elements:
Name | Description | Field Type |
---|---|---|
| Enables markup options (bold, italic and underline) | boolean |
| Specifies the allowed headline types | array |
| Enables the creation of quoted text | boolean |
| Enables text alignment (left, center, right, justified) | boolean |
| Enables hyperlinks support | boolean |
| Enables the text color overrides NOTE: using this feature results in inline styles being rendered in the HTML. It will therefore have more specificity than CSS definitions made in the module itself | boolean |
| Allows the creation of lists (numbered or bulleted) | boolean |
This is a sample UI configuration, for a field called description
:
Arrays
We support arrays as well, which is very useful when we need a repeater field (e.g. an image gallery module).
To define an array use this structure:
Dropdowns
We support dropdowns as well.
Template (Handlebars Template)
This is where the HTML structure of the module is defined. To allow dynamic capabilities, we support Handlebars syntax ( https://handlebarsjs.com/ ).
By using the Handlebars variables you will be able to access every piece of information that was created through the editor UI.
For example, to access the variable called “headerTitle”:
In a similar way you can access something that was defined inside settings:
This is of course a very simple example, but even complex layouts can be achieved by using the Handlebars capabilities, such as iterations, conditional rendering, etc.
For this we suggest taking a look at their official documentation:
https://handlebarsjs.com/guide/builtin-helpers.html
Documentation for Handlebar Helpers
We currently provide all the Handlebar helpers listed on this documentation website: https://documentation.styla.eu/custom-modules/handlebars-helpers/helpers-index. One thing you can build using these helpers is product details page as custom module. More helpers will be added in the future, for instance, some facilitating building product listing (category grids) pages as custom modules.
JS (Javascript)
If your module requires some dynamic functionality that can only be achieved with Javascript, you can develop a script that will be executed right after your custom module is mounted.
The JS snippet needs to be a function that will accept one parameter, which will be the custom module main wrapping DOM element. This will be useful in order to be able to target the correct element without having to rely on id or class names. This will additionally allow the safe use of multiple instances of the module on the same page without causing conflicts.
In addition to that we can as well return a cleanup function, which will be called when the element is unmounted. This can be useful e.g. for removing click listeners etc.
This is a very basic example:
The "CUSTOM_MODULE_NAME"
needs to match your module name defined in the front configuration. The function can take up to 5 parameters. They might change from time to time on the Styla end.
The cleanup function is optional and can be omitted.
Full Example
In this example, we are going to create a “Social Sharing” module:
The final result is a Social Sharing element, where the final user can click on a specific service and share the current page on the selected Social Media platform
Content creators need to be able to upload images with the Social Media logos. In addition they need to be able to rearrange the items, type a title which will be shown on mouseover, disable an element without deleting it.
Content creators need to be able to set a title for the whole module
Content creators need to be able to adjust the spacing between the icons and the icon size via a simple UI
Schema (Data structure)
We will first define a standard text field which we will use as a call to action phrase naming it headerTitle
. In addition to this we will have a repeater field which we will call icons. Each of these elements will contain the following data:
isShown
: a boolean to hide/show the iconimage
: the icon image. We will use the Styla image uploader for this.title
: the title that will be shown on mouseover on the iconidentifier
: an identifier of the type of Social Network. This will be used by the JS file in order to determine how the destination URL will be constructed.
We also want to support a couple of settings:
iconsSize
: the size of the icons in pixelsiconsPadding
: the spacing between icons in pixels
For these 2 settings we want to use the SliderField
widget and also set some predefined values on the slider.
The final content of schema.json
will therefore look like this:
Once we have this we can already store it in a file, upload it in a web host (or S3 bucket) and then create the Custom Module configuration in the Styla Organization Manager (admin.styla.eu):
After this, the module will already be available for use within the Editor. Of course there will not be any preview (since the template
part is still missing) but we can already test the Editor part and make sure that it looks as we intended.
After populating the module with dummy data we can even check the generated JSON (by clicking on Edit JSON on the bottom left of the module) to double-check the data structure. This can be particularly useful when creating the Handlebars template.
Template (Handlebars Template)
As mentioned above, the single icon is a repeater field, since the user can add an unlimited number of these items. Therefore, we need to rely on the iteration functionality provided by Handlebars. In addition to that, we also want to access the settings from each element of this iteration. For this, we will use the shortcut @root.
The final template will look like this:
We also used conditional rendering to show/hide the icon based on the value of isShown
.
As you can see, the field called identifier is output with an attribute called data-service-name. This will be used by the JS to construct the destination URL.
Once this is done we can save this in a .handlebars file and add it to our front configuration in the Organization Manager.
JS (JavaScript)
The module is now rendered in the preview, but we don’t have any functionality. What we want is to open the correct destination link for sharing, and we also want to pass the current location to this URL. We will do this in JavaScript.
As mentioned above, our function will receive the module DOM element as a parameter (wrapperElem
). We will use this information to iterate through every child <a>
element (the single icon) and append a click listener to it. Then, on click, we will read the data-service-name attribute in order to understand which is the type of service. Finally, we will construct the destination URL based on the service and open the link. The document location and the meta information will be scraped directly from the page via document.querySelector
:
The Custom Module is done!
Further resources
Video Demo:
https://monosnap.com/file/J7466WoiTDSEYyQy6Z2whFcXM0lvDD
The final JSON files:
https://static-cdn.styla.com/custom-modules-demo/customModule.js
https://static-cdn.styla.com/custom-modules-demo/customModuleTemplate.handlebars
https://static-cdn.styla.com/custom-modules-demo/customModuleSchema.json
Live Playground of this demo (JSFiddle):
https://jsfiddle.net/antoniocosentino/a4twjmx9/
Viewing JSON data for a module/page:
In order to see the full JSON data structure used for rendering a module or a page, simply add /json at the end of URL generated by http://editor.styla.eu .
So the paths to get the JSON look like this respectively:
Page:https://editor.styla.eu/${accountName}/pages/${pageId}/json
Module:https://editor.styla.eu/${accountName}/pages/${pageId}/modules/${moduleId}/json