Skip navigation

Integrating your own content editing features

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 Kontent UI and take the content editing experience to another level.

Premium feature

Custom elements require a Professional plan or higher.

Table of contents

    A Custom element is essentially a small HTML application that exists in a sandboxed <iframe> and interacts with the Kentico Kontent 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 Kontent 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 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 Kontent. To use the API, you need to include it in your HTML source code.

    • HTML
    <script src="https://app.kontent.ai/js-api/custom-element.js"></script>
    <script src="https://app.kontent.ai/js-api/custom-element.js"></script>

    Adding CSS styles

    By including Kentico Kontent 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. kentico-icons-v1.6.0.woff 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.

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

    Getting the element value

    Securing your Custom element

    When displaying the Custom elements in the Kentico Kontent 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.kontent.ai. For more details, see MDN Web Docs.

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

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

    Specifying the JSON parameters

    You can make certain properties of the Custom element configurable by specifying the JSON parameters. See the init method in the API Reference for more details.

    • JavaScript
    CustomElement.init((element, _context) => { // Set up the Custom element using JSON parameters setupColorPicker(element.config.outputFormat); });
    CustomElement.init((element, _context) => { // Set up the Custom element using JSON parameters setupColorPicker(element.config.outputFormat); });

    Setting the element value

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

    • JavaScript
    CustomElement.setValue("#" + color);
    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.

    • JavaScript
    CustomElement.setHeight(height);
    CustomElement.setHeight(height);

    Disabling changes on published content

    Use the 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 an older version, or when a user doesn't have sufficient permissions to edit content.

    See the onDisabledChanged method specification in our API Reference.

    • JavaScript
    CustomElement.onDisabledChanged(updateDisabled);
    CustomElement.onDisabledChanged(updateDisabled);

    Final HTML code

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

    • HTML
    <!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.kontent.ai/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 Kontent CustomElement.setValue("#" + color); } }); picker.enter(); } function updateSize() { // Update the Custom element height in the Kentico Kontent 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 Kontent UI) console.error(err); setupColorPicker(); updateDisabled(true); } } initCustomElement(); </script> </body> </html>
    <!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.kontent.ai/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 Kontent CustomElement.setValue("#" + color); } }); picker.enter(); } function updateSize() { // Update the Custom element height in the Kentico Kontent 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 Kontent UI) console.error(err); setupColorPicker(); updateDisabled(true); } } initCustomElement(); </script> </body> </html>

    color-picker.html is now ready to use.

    2. Secure hosting

    Custom elements are HTML applications loaded in 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.

    Sandboxing the <iframe>

    The HTML5 sandbox attribute is used on the iframe to separate an extension from the Kentico Kontent app. The following sandbox flags are enabled:

    • allow-forms – allows form submission
    • allow-scripts – allows JavaScript to run inside the iframe
    • allow-popups – allows popups
    • allow-same-origin – allows the document to maintain its origin, pages loaded from  https://example.com/ will retain access to that origin’s data

    If no options are specified for the sandbox then the iframe can only display basic HTML.

    Learn more about the sandbox attribute and the restrictions it brings at W3Schools.

    3. Displaying a Custom element in Kentico Kontent

    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 .
    2. Choose an existing content type or create a new one by clicking Create new.
    3. Drag in a Custom element element from the right and give it a name.
    4. Add your hosted code URL.
    5. (Optional) Fill in the JSON parameters.
    6. Click Save changes.

    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 Kontent 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 in the UI

    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. Leave the field empty if you don't need it.

    Warning: Never store your API keys or any other sensitive data in the JSON parameters field, it's not secure!

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

    The set up for a color picker custom element.

    How your Custom element might appear inside a content type.

    4. Final result

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

    A color picker inside a content item.

    How your Custom element might appear inside a content item.

    Sample Custom elements & devkit

    We have a variety of sample Custom elements prepared for you to use. You can see how they look in action in the Custom Elements Gallery or look at their code in the custom elements GitHub repository. By using these prepared elements, you won't need to start implementing your UI extensions completely from scratch.

    The examples are open source so they can be fit to your specific needs. 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. Find inspiration in the existing sample custom elements at GitHub and create your own.

    You can also take advantage of our Custom elements devkit, which we created to help you prepare your Custom elements for production. The devkit includes a Kentico-Kontent-like wireframe and mocked API to enable a seamless debugging experience.

    What's next?

    • Check out our Custom Elements API specification to see all the available API methods.
    • See how you can use custom elements for integration with 3rd party services such as Shopify and Optimizely.