Integrating your own content editing features (BETA)

Extend the Kentico Cloud UI with 3rd party services by using Custom elements.

Custom elements (BETA)

Custom elements feature is still in BETA and under heavy development. The feature will be progressively deployed to Kentico Cloud. If you have any feedback, let us know by using the chat button in the bottom-right corner.

Premium feature

Custom elements require an Enterprise plan. See Pricing for more details.

Imagine your content editors want to write their blog posts in a simple markup language or you want to use an external service for storing and managing your assets. In situations like these, Custom elements help you with extending the built-in functionality of the Kentico Cloud UI and take the content editing experience to another level.

A Custom element is essentially a small HTML application that exists in a sandboxed <iframe> and interacts with the Kentico Cloud app through the Custom Elements API. So, apart from using the default content type elements such as Rich text or Linked items element, you can create your own elements according to your needs.

The implementation of Custom elements depends completely on your use-case scenario. It can be implemented as a simple HTML app mixed with a bit of JavaScript or an advanced app based on your favorite framework.

To get you started, follow a step-by-step guide on how to extend the Kentico Cloud app with a basic color picker. This Custom element allows you to choose a color from the palette and sets it as a HEX string. The color picker used in this guide is based on one of our sample Custom elements.

1. Creating a Custom element

Prepare an HTML web page containing your Custom element specification while utilizing the Custom Elements API methods.

Custom elements (BETA) require the latest SDK version

When using Custom elements in your project, make sure you have the latest SDK version so that your app can display the Custom elements correctly.

Including the Custom Elements API

The Custom Elements API is a JavaScript API that allows you to create Custom elements for Kentico Cloud. To use the API, you need to include it in your HTML source code.

<script src="https://app.kenticocloud.com/js-api/custom-element.js"></script>

Adding CSS styles

By including Kentico Cloud default styles, you can make your Custom element look consistent with the rest of the UI.

The public GitHub repository contains:

  • custom-element.css – CSS stylesheet
  • kentico-icons-v1.6.0.woff – Font file
  • examples.html – An HTML page containing the implementation details and an HTML markup of some of the basic elements

We recommend you clone the files and host them locally yourself. The kentico-icons-v1.6.0.wofffile needs to be hosted in the same directory as the CSS stylesheet to be properly linked.

Alternatively, you can link the CSS stylesheet in your HTML source code as seen in the code below.

<link rel="stylesheet" type="text/css" href="https://kentico.github.io/custom-element-samples/shared/custom-element.css">

Getting the element value

When initializing a Custom element, you need to set up its value as seen in the code below.

CustomElement.init((element, _context) => {
  // Set up the element with initial value
  setupColorPicker(element.value);
});

Setting the element value

When the element value changes, you need to save the value to the Kentico Cloud UI. See the specification of the setValue method in our API Reference.

CustomElement.setValue('#' + color);

Specifying the height of the element

The height value of the element can be set using the setHeight method. We strongly recommend you set the value in the shortest time possible to avoid screen flickering while scrolling and other related issues.

If you need to load some time-consuming resources in your Custom element and then set the final height of the element, try first setting at least some default height value and then update the final height once the user interacts with the Custom element. By doing so, you will not experience any problems when loading the content item containing the Custom element.

When the height value is set correctly, you won't see the scrollbar when displaying the element in the UI.

You can find an example of setting a dynamic height and reacting to the window 'resize' events in one of our sample Custom elements, Markdown editor.

CustomElement.setHeight(height);

Disabling changes on published content

Use onDisabledChanged method to define what should happen with the Custom element when it's disabled for editing. This way, you can prevent any unexpected behavior that might result from trying to update such Custom element.

When disabled, the element is in the read-only mode. This means the element is visible in a content item but cannot be changed. Custom element can be disabled when, for example, the content is published, when displaying the element in one of the revisions, or when a user doesn't have sufficient permissions to edit content.

See the method specification in our API Reference.

CustomElement.onDisabledChanged(updateDisabled);

Final HTML code

You can see the completed HTML code below or in our sample elements repository on Github.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Color Picker</title>
    <!-- Include jQuery library -->
    <script src="https://cdn.jsdelivr.net/npm/jquery@3.3.1/dist/jquery.min.js"></script>
    <script src="https://kentico.github.io/custom-element-samples/ColorPicker/color-picker.min.js"></script>
    <link rel="stylesheet" href="https://kentico.github.io/custom-element-samples/ColorPicker/color-picker.min.css">

    <!-- Include the Custom Elements API-->
    <script src="https://app.kenticocloud.com/js-api/custom-element.js"></script>

    <!-- Custom element CSS styles -->
    <style>
        /* We recommended you always set margin to zero to avoid problems when displaying the element in UI */
        body {
            margin: 0;
        }

        div.color-picker-box {
            width: 100%;
            padding: 30px 0 30px 0;
            text-align: center;
            z-index: 1;
        }
      
        .color-picker.static {
            display: inline-block !important;
            position: static !important;
            top: 0 !important;
            left: 0 !important;
        }
      
        .disabled_overlay {
            position: fixed;
            z-index: 10;
            cursor: not-allowed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            opacity: 0;
        }
    </style>
</head>
<body>
    <!-- Custom element HTML -->
    <div class="disabled_overlay"></div>
    <div class="color-picker-box">
        <section id="color-picker"></section>
    </div>

    <!-- Custom logic of the Custom element -->
    <script>
        var isDisabled = false;
      
        function updateDisabled(disabled) {
            isDisabled = disabled;
            if (disabled) {
                $('.disabled_overlay').show();
            }
            else {
                $('.disabled_overlay').hide();
            }
        }
      
        function setupColorPicker(hexColorValue) {
            const container = document.querySelector('#color-picker');
            const picker = new CP(container, false, container);
            picker.self.classList.add('static');
            if (!!hexColorValue) {
                picker.set(hexColorValue);
                container.parentNode.style.backgroundColor = hexColorValue;
            }
          
            picker.on("change", function (color) {
                container.parentNode.style.backgroundColor = '#' + color;
                if (!isDisabled) {
                    // Send updated color to Kentico Cloud
                    CustomElement.setValue('#' + color);
                }
            });
          
            picker.enter();
        }
      
        function updateSize() {
            // Update the Custom element height in the Kentico Cloud UI
            const height = $("html").height();
            CustomElement.setHeight(height);
        }
      
        function initCustomElement() {
            try {
                CustomElement.init((element, _context) => {
                  // Setup with initial value and disabled state
                  setupColorPicker(element.value);  
                  updateDisabled(element.disabled);
                  updateSize();
                });
                // React when the disabled state changes (e.g. when publishing the item)
                CustomElement.onDisabledChanged(updateDisabled);
            } catch (err) {
                // Initialization with the Custom elements API failed 
                // (page displayed outside of the Kentico Cloud UI)
                console.error(err);
                setupColorPicker();
                updateDisabled(true);
            }
        }
      
        initCustomElement();
      
    </script>
</body>
</html>

The color-picker.html file is now ready to use.

2. Secure hosting

Custom elements are HTML applications loaded into an <iframe>. They need to be hosted so the browser can fetch the file. The hosting of your Custom elements source code needs to be done on your end.

  • Always use a secured connection (HTTPS) for your hosted code URL. For example, https://example.com/custom.html.
  • If you first want to test your implementation locally, you need to generate a self-signed HTTPS certificate.

3. Displaying a Custom element in Kentico Cloud

After implementing a Custom element and providing hosting for your source code, you need to add the element to a content type in the UI.

  1. From the app menu, choose Content models.
  2. Choose an existing content type or create a new one by clicking Create new.
  3. Drag & drop Custom element into the element area and give it a name.
  4. Add your hosted code URL.
  5. (Optional) Fill in the JSON parameters.
  6. Click Save.

A few things to keep in mind:

  • When adding your self-hosted code URL, you need to use an HTTPS protocol. For example, https://example.com/hello.html.
  • If you set a Custom element as required, Kentico Cloud will test if the requirement is fulfilled by checking if the element contains any value other than null. Everything else is considered a valid value and thus won't generate an error message when an item containing the element gets published.

JSON parameters

If you want to have your Custom element reusable and configurable, fill in the JSON parameters field. By applying JSON to the element, you can, for example, use the element in different content types or have a customizable layout for the element. All this depends on your preferences. You can leave the field empty if you don't need any of this.

Note: Never store your API keys in the JSON parameters field, it's not secure!

In the example below, JSON is used to specify the output format.

4. Final result

After creating a content item containing the Custom element, the result will be similar to the one below.

Securing your Custom element

When displaying the Custom elements in the Kentico Cloud UI, we recommend you always secure your implementation.

You can use the X-frame-option HTTP response header to specify an allowed origin, in this case, https://app.kenticocloud.com. For more details, see MDN Web Docs.

By specifying the origin, you can prevent other potentially harmful hosts from accessing your data by behaving as a valid host, for example by faking the initial data.

Sample Custom elements

We prepared two ready-to-use sample Custom elements as a source of inspiration for you. This way, you don't need to start implementing your UI extensions completely from scratch.

  • Color picker – allows users to choose a color from the palette and sets it as a HEX string
  • Markdown editor – allows content editors to write content in a simple markup language

The examples are open source so they can be fit to your specific needs. See the hosted code URLs below:

If you plan on using these sample elements in your own production project, we recommend you clone the repository. By doing so, you will not be affected by the possible changes made to the Custom elements in the future.

What's next?

Check out our Custom Elements API specification to see all the available methods.