When modeling content, you frequently stumble upon the need of storing data in specific structures that go beyond conventional types like string, number or list of options. Typical examples are countries and states. You can not use a free text field for this unless you fancy giving editors free rein. So how can you extend the system and store such data?
Why should you not use a free text field? Apart from the fact that editors would have to write country names every time, you would end up with a pile of unstructured data, many duplicates, and typos. Because not all countries in the world have states, you also need a bit of business logic in the selector. Therefore, a simple dropdown would not be an ideal solution either.
First of all, I want to emphasize that the word custom does not mean you need to implement it. You don't even have to download, compile, or install it. No, to use a custom element within Kentico Cloud, you only need to copy and paste its URL. But I'll get to that later. First, let me explain what a custom element is.
So what would that country and state selector look like? It is an empty page with two dropdown selectors. The second dropdown showing states is displayed if the selected country has any states. It does not persist any changes yet, because there is no parent window to communicate with (Kentico Cloud).
If you are interested in using an existing custom element, feel free to jump to `Using a Custom Element section`.
Building a Custom Element
The country and state selector covers a use case of country-related content items. It could be your company's offices, your country's embassies or trips of your favorite travel agency. All these items are related to a specific country/state.
You see, when your data structure goes beyond standard data types, you may need a custom element. The best place to look for one is our GitHub repository. If you can't find one matching your requirements, you're lucky! You get to enjoy all the fun of building one :-), so just follow my story of country and states selector.
How Do I Start?
While you can start on a green field with just Notepad, we prepared a DevKit for you to speed up less interesting tasks like minimizing assets, including Kentico Cloud styles and so on. The DevKit is available on GitHub, and you can start by cloning its repository:
And installing missing node modules:
To create a new custom element, navigate to the `/client/custom-elements` folder and create a new folder for it. You will also need to create two files:
The view of your custom element in Pug.
Which Framework Should I Use?
The devkit works with any JS framework, so feel free to use your favorite one or plain JS. These days I work with React.js a lot, so I decided to use that. I needed to install two additional packages at the devkit root:
How Does a Custom Element Communicate with Kentico Cloud?
Every component, even if it is just a simple text field, needs to communicate with Kentico Cloud. They need to exchange data when a content item is opened or updated to make sure editors see the right values and their work is persisted. The component also needs to prevent updates to already published content items and tell Kentico Cloud how much room it needs to render correctly.
The Kentico Cloud Custom Elements API provides methods for all these cases. Take a look at my (simplified) implementation of the country selector in code.tsx:
Kentico Cloud initiates the custom element by invoking CustomElement.Init and by providing all data within element and _context objects. I used that event to initialize my component with data (element.value) and flag describing whether the component should allow editors to change values (element.disabled).
My selector uses two data fields - countryCode and stateCode - to persist the editor's selection. The element.value object will, therefore, be null (no value or brand new content item) or look like this:
The last parameter (customElementApi) enables my React component to call method setValue() of Custom Element API that persists data in Kentico Cloud. My selector invokes it every time a user changes a country or state to make sure his or her choice is persisted.
As the selector currently uses the same height for all use-cases, it is set to 250px using method setHeight().
For the full list of available methods check out the API reference in Kentico Cloud documentation.
Building and Deploying Custom Elements
When you are finished with the implementation, you should first reward yourself with a beer or two. After that, it's time to build and deploy it for the whole world to see. The first step towards that is to build the custom element:
As the custom element is represented by a single HTML file, you can host it pretty much everywhere (Heroku, Surge, your hosting space, etc.). However, I decided to host it on GitHub in the Kentico Custom Element Samples repository as it already hosts a few custom elements and it is the best place to share it with other developers. This way anyone can find my selector quickly and use it within their projects. The repository is also using GitHub pages, so all elements hosted there can be directly referenced using URL.
Using a Custom Element
So the custom element is deployed and accessible online (we have its URL). Cool, that was the hard part. Now let's use that custom element in Kentico Cloud.
When you open a content type definition, you can drag&drop the generic Custom element to the list of fields. In the configuration of your new field, there is a textbox for the custom element URL. As my country and state selector is hosted on GitHub, the URL looks like this:
Note that custom elements always need to be accessible via HTTPS to ensure secure communication between Kentico Cloud and the custom element.
That's it. No other steps needed. Go ahead and open any content item based on the updated content type and try it out.
The same way you can also leverage any custom element from our daily growing list and please your editors with a great user experience when dealing with specific data structures.
Get $150 for Your Custom Element
Country and state selection are pretty common when working with content. So would it make sense for every developer to create their own custom selector for it? Probably not. As I already created one it's easy for everyone else to use it - just reference its URL within custom element configuration.
We love it when developers help each other and sharing custom elements would save your fellow developers tons of time. And we also like to play. That's why we organized a contest during March 2019 that rewards custom element contributors. The rules are simple - create a custom element and contribute it to our samples repository on GitHub. We will reward the top 10 best custom elements with a $150 Amazon voucher! That gets you an Amazon Echo, Apple Pencil or 20x USB cables for your phone (that gets my USB cable consumption covered for a year)!
To find out more and enter, visit www.kenticocloud.com/blog/custom-elements-contest.
*UPDATE: The contest deadline has been pushed to April 14th*