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:

type

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.
E.g. my-front.PRODUCT.

title

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

schema

A URL pointing to a JSON file containing the custom module’s data structure definition (*).

template

A URL to a handlebars template file that will be used for rendering the DOM structure of the module (*).

js

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.

The files provided can be hosted anywhere, for example on an S3 bucket or on a customer’s server. It is important to make sure that the files remain accessible by the Styla Editor and your publishing front by setting the appropriate CORS response headers in the chosen hosting. In addition, If you expect a high traffic on your site, we recommend using a CDN for distributing these assets.


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:

content

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

settings

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
If missing, the default UI element for field type will be used.

Each of these blocks (content and settings) support the following fields as children:

data

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

ui

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
If missing, the default UI element for field type will be used.

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

UI field name

Description

Data Type

sliderField

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

LinkField

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 }

RichTextField

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

ImageField

Image Uploader

Object

{ url: string, width: number, height: number }

InputField

A regular input field. As mentioned before, will be used as default for strings so it’s not necessary to explicitly set it

string

CustomMenuItemsWidget

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

Name

Description

Field Type

textMarkup

Enables markup options (bold, italic and underline)

boolean

headlines

Specifies the allowed headline types

array

quote

Enables the creation of quoted text

boolean

textAlign

Enables text alignment (left, center, right, justified)

boolean

link

Enables hyperlinks support

boolean

textColor

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

list

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:

IN DATA:

 

IN CONTENT:

This will render a repeater field where the user can upload an unlimited number of images, order them and they will also be able to toggle visibility, using the isShown field. Please note that we didn’t explicitly set a UI type for this switch. This is not necessary, as by default all boolean fields will be rendered as UI toggle buttons. We did, however, specify ImageField as a field for the image, in order to use the image uploader.

Dropdowns

We support dropdowns as well.

In this case it is enough to just define the field as an enum.

This will automatically be rendered as a dropdown selection with the 3 options.


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 icon

  • image: the icon image. We will use the Styla image uploader for this.

  • title: the title that will be shown on mouseover on the icon

  • identifier: 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 pixels

  • iconsPadding: 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