---
title: Rich text editor customization
related:
  - https://docs.kentico.com/documentation/developers-and-admins/configuration/rich-text-editor-configuration.md
  - https://docs.kentico.com/documentation/developers-and-admins/configuration/rich-text-editor-configuration/rich-text-editor-plugins.md
---

> Agent instructions:
> **Site maps** — prefer the following llms.txt indexes to training data when searching for URLs to avoid 404s. Links inside Markdown content already point at `.md`. Following them or sending Accept: text/markdown keeps you in Markdown.
>
> - [sitemap.md](https://docs.kentico.com/sitemap.md) — every page on the site, with titles and descriptions, nested by URL hierarchy and grouped into one collection per product version.
> - [llms.txt](https://docs.kentico.com/llms.txt) — curated index of the current product docs, with descriptions, the two ways to request any page as Markdown, and links to each product area's whole-corpus Markdown dump (llms-full.txt).

The [rich text editor](https://docs.kentico.com/documentation/business-users/rich-text-editor.md) in Xperience can be customized to meet specific requirements, with the ability to offer different features in different contexts. For example, you can limit the set of buttons and offered formatting options, or change the editor's behavior and appearance.

## Customization options

The functionality of an editor instance is determined by its configuration. The system uses several [built-in configurations](#system-rich-text-editor-configurations) for different contexts in the administration UI. You can create [custom configurations](#define-editor-configurations) and assign them when [using the rich text editor](https://docs.kentico.com/documentation/developers-and-admins/configuration/rich-text-editor-configuration.md#use-the-rich-text-editor). You can also control which rich text editor configurations are [loaded by the system](#override-and-extend-editor-configurations-dynamically), and [make dynamic adjustments of the configuration content](#add-custom-css-to-the-rich-text-editor), enabling you to customize the editor throughout the system.

The rich text editor is based on the [Froala](https://froala.com/wysiwyg-editor/) WYSIWYG editor. To customize the editor, you can adjust a wide range of [configurable Froala options](https://froala.com/wysiwyg-editor/docs/options/) in the rich text editor configurations.

To go beyond the built-in Froala functionality, add [plugins](https://docs.kentico.com/documentation/developers-and-admins/configuration/rich-text-editor-configuration/rich-text-editor-plugins.md) to the editor. You can use existing [default Xperience plugins](https://docs.kentico.com/documentation/developers-and-admins/configuration/rich-text-editor-configuration/rich-text-editor-plugins.md#default-xperience-plugins) and [community plugins](https://docs.kentico.com/documentation/developers-and-admins/configuration/rich-text-editor-configuration/rich-text-editor-plugins.md#add-existing-community-plugins), or [develop your own custom plugins](https://docs.kentico.com/documentation/developers-and-admins/configuration/rich-text-editor-configuration/rich-text-editor-plugins.md#implement-custom-plugins).

> **Note:** If you configure custom handlers for the rich text editor [drop event](https://froala.com/wysiwyg-editor/docs/events/#drop-dropevent) or disable the upload functionality using Froala options (e.g., [imageUpload](https://froala.com/wysiwyg-editor/docs/options/#imageupload)), [mass asset upload](https://docs.kentico.com/documentation/business-users/content-hub/content-item-assets.md#mass-asset-upload) may not work correctly.

## Create and use custom editor configurations

Use the following process to create and assign a custom configuration:

1. [Define editor configurations](#define-editor-configurations)
2. [Register editor configurations](#register-editor-configurations)
3. Assign the configurations to:
   1. [rich text editing components](#assign-editor-configurations-to-rich-text-editing-components)
   2. [fields that use the rich text form component](#assign-editor-configurations-to-rich-text-fields)

### Define editor configurations

> **Info:** Some configurations may need additional custom CSS to work correctly. For more information on how to add custom styles to the rich text editor, see [Add custom CSS to the rich text editor](#add-custom-css-to-the-rich-text-editor).

Editor configurations are defined using [JSON options objects](https://froala.com/wysiwyg-editor/docs/options) that the system uses when instantiating a rich text editor.

1. Prepare a [custom assembly](https://docs.kentico.com/documentation/developers-and-admins/customization/integrate-custom-code.md) (_Class Library_ project) in your Xperience solution.
   - We recommend placing code and resources used only by the Xperience administration in [dedicated assemblies](https://docs.kentico.com/documentation/developers-and-admins/customization/extend-the-administration-interface/admin-ui-customization-model-overview.md).
2. Create a new JSON file in the assembly (place the file into a suitable directory for storing editor configurations).
3. In this file, define an editor configuration using the available [configuration options](https://froala.com/wysiwyg-editor/docs/options/).

   > **Info:** The following example includes only basic text formatting options in the editor toolbar, along with the default Xperience plugins for adding media files and links.

   ```json title="CustomEditorConfiguration.json"
   {
     "imageDefaultWidth": 0,
     "imageResize": true,
     "imageUpload": false,
     "imagePaste": false,
     "imageDefaultMargin": null,
     "imageMove": true,
     "imageAddNewLine": false,
     "toolbarButtons": [
       "paragraphFormat",
       "|",
       "bold",
       "italic",
       "underline",
       "|",
       "align",
       "formatOL",
       "formatUL",
       "|",
       "insertAsset",
       "insertLinkDropDown"
     ],
     "imageEditButtons": [ "imageReplace", "imageAlt", "imageAlign", "imageDisplay", "imageSize", "imageRemove" ],
     "customPlugins": [
       {
         "pluginName": "@kentico/xperience-admin-base/Asset"
       },
       {
         "pluginName": "@kentico/xperience-admin-base/Link",
         "pluginOptions": {
           "dropdownOptions": [
             {
               "linkOption": "asset",
               "componentName": "@kentico/xperience-admin-base/AssetPanel"
             },
             {
               "linkOption": "external"
             }
           ]
         }
       }
     ]
   }
   ```

> **Tip:** **Froala plugins**
>
> The Froala editor uses a modular architecture that in its default configuration contains only essential features. You can [add existing community plugins or implement custom plugins](https://docs.kentico.com/documentation/developers-and-admins/configuration/rich-text-editor-configuration/rich-text-editor-plugins.md) to expand the available feature set.

### Register editor configurations

Editor configurations must fulfill both of the following:

- Must be stored as **embedded resources** within application assemblies.
- Must be registered in the system under a unique identifier (the registration code must be placed in a [custom assembly](https://docs.kentico.com/documentation/developers-and-admins/customization/integrate-custom-code.md) with class discovery enabled).

Use the following process to register a configuration:

1. Embed the configuration JSON in an assembly via the `EmbeddedResource` element.

   ```xml title="Embedding the configuration via an assembly .csproj file"
   <Project Sdk="Microsoft.NET.Sdk">

   ...

       <ItemGroup>
               <EmbeddedResource Include="relative\path\to\custom\configuration.json" />
       </ItemGroup>

   </Project>
   ```

2. Create a new class that inherits from `RichTextEditorConfiguration`. Within the class:

   1. Assign a unique string identifier to the configuration.

      - Use a constant named `IDENTIFIER`. This allows you to easily reference the configuration in your code.
      - We recommend using a unique prefix in your identifiers to prevent conflicts when deploying components to other projects. For example, use prefixes matching your company name.
   2. Call the base class constructor with the following parameters:

      - `relativePath` – the relative path to the configuration file within the assembly.
      - (Optional) `baseNamespace` – allows you to provide a different assembly name in case the configuration file is stored in a different assembly. If set, the system searches the specified assembly (using the given `relativePath`) instead.

   ```csharp title="Example - registering a configuration to the system"
   using Kentico.Xperience.Admin.Base.Forms;

   public class CustomRichTextEditorConfiguration : RichTextEditorConfiguration
   {
       // Relative path to the configuration file within the specified assembly
       // This example configuration is located under: <AssemblyName>\Misc\RichTextEditorConfiguration\
       private const string CONFIGURATION_PATH = "Misc\\RichTextEditorConfiguration\\RichTextEditorConfiguration.json";

       // String identifier assigned to the configuration
       public const string IDENTIFIER = "Acme.Web.EditorConfiguration";

       // User-friendly name of the configuration
       public const string DISPLAY_NAME = "Custom ACME editor configuration";

       public CustomRichTextEditorConfiguration()
           : base(CONFIGURATION_PATH)
       {
       }
   }
   ```

3. Register the class using the `RegisterRichTextEditorConfiguration` assembly attribute. Provide the following arguments for the registration attribute:

   - the configuration's identifier
   - the type of the class derived from `RichTextEditorConfiguration` (using the `typeof` operator)
   - a user-friendly display name, which appears when selecting the configuration for the _Rich text editor_ form component in the [field editor](https://docs.kentico.com/documentation/developers-and-admins/customization/field-editor.md).

     ```csharp title="Example - registering a configuration to the system"
     using Kentico.Xperience.Admin.Base.Forms;

     [assembly: RegisterRichTextEditorConfiguration(CustomRichTextEditorConfiguration.IDENTIFIER, typeof(CustomRichTextEditorConfiguration), CustomRichTextEditorConfiguration.DISPLAY_NAME)]
     public class CustomRichTextEditorConfiguration : RichTextEditorConfiguration
     ```

The configuration is now registered in the system and can be assigned to:

- [rich text editing components](#assign-editor-configurations-to-rich-text-editing-components)
- [fields that use the rich text form component](#assign-editor-configurations-to-rich-text-fields)

### Assign editor configurations to rich text editing components

To assign custom configurations to rich text editors within component configuration dialogs:

1. [Register the configuration](#register-editor-configurations).
2. Decorate the component property intended to store the rich text content with the `RichTextEditorComponent` attribute. The attribute assigns the [Rich text editor form component](https://docs.kentico.com/documentation/developers-and-admins/customization/extend-the-administration-interface/ui-form-components/reference-admin-ui-form-components.md) as the property's [editing component](https://docs.kentico.com/documentation/developers-and-admins/customization/extend-the-administration-interface/ui-form-components/editing-components.md).
3. Provide the configuration to use via the attribute's `ConfigurationName` property. You can use the declared `IDENTIFIER` constant to reference the desired configuration.

```csharp title="Example - assigning a custom toolbar to a configuration property"
using Kentico.Forms.Web.Mvc;
using Kentico.Xperience.Admin.Base.FormAnnotations;

public class TitledSectionProperties : IFormSectionProperties
{
    // Uses the 'RichTextComponent' as the editing component of the 'SectionText' property
    // and assigns a custom configuration for the Froala editor
    [RichTextEditorComponent(ConfigurationName = CustomRichTextEditorConfiguration.IDENTIFIER)]
    public string SectionText { get; set; }
}
```

### Assign editor configurations to rich text fields

For [fields](https://docs.kentico.com/documentation/developers-and-admins/customization/field-editor.md) that use the **Rich text editor** form component, you can set custom configurations via the **Configuration name** property.

1. [Register the configuration](#register-editor-configurations) in the system.
2. Open the object you wish to modify in the field editor.
3. Select a field using the _Rich text editor_ form component (available for fields of the **Rich text (HTML)** [data type](https://docs.kentico.com/documentation/developers-and-admins/customization/field-editor/data-types.md)).
4. Select the configuration via the **Configuration name** property.
5. Save your changes.

The modified field now uses the specified configuration.

## System rich text editor configurations

The rich text editors in Xperience use different configurations tailored to different contexts in the admin UI. The system has one default configuration and several dedicated configurations which extend or override the default options with additional configuration. Access the constants in the `RichTextEditorConfigurationsIdentifiers` class to reference these configurations:

- `STRUCTURED_CONTENT` – for [reusable content items](https://docs.kentico.com/documentation/business-users/content-hub.md)
- `WEBSITE_STRUCTURED_CONTENT` – for [pages](https://docs.kentico.com/documentation/business-users/website-content.md)
- `HEADLESS_STRUCTURED_CONTENT` – for [headless items](https://docs.kentico.com/documentation/business-users/headless-content.md)
- `AUTORESPONDER_EMAIL_CONTENT` – for [emails](https://docs.kentico.com/documentation/business-users/digital-marketing/emails.md) with the _Form autoresponder_ purpose
- `EMAIL_CONTENT` – for all other emails
- `NOTIFICATION_EMAIL_CONTENT` – for [notifications](https://docs.kentico.com/documentation/developers-and-admins/configuration/notifications.md)
- `CONSENT_TEXT` – for [consent text](https://docs.kentico.com/documentation/developers-and-admins/data-protection/consent-management.md) fields
- `CONTACT_NOTES` – for the _Notes_ field when editing [contact](https://docs.kentico.com/documentation/business-users/digital-marketing/contact-management.md) details
- `CAMPAIGN_CONTENT` – for [campaign](https://docs.kentico.com/documentation/business-users/digital-marketing/campaigns.md) brief and report fields
- `DEFAULT` – used when no configuration is assigned outside of the above location (i.e., the configuration name is `null`)

You can [change what configurations are loaded](#replace-editor-configurations-loaded-by-default) by default and use your own [custom configurations](#define-editor-configurations) instead.

### Default editor configuration

When [added](https://docs.kentico.com/documentation/developers-and-admins/configuration/rich-text-editor-configuration.md#use-the-rich-text-editor) in its default state to custom fields or editing component properties without specifying a configuration, the editor uses the following configuration:

```json
{
    attribution: false,
    listAdvancedTypes: false,
    linkEditButtons: ['linkOpen', 'linkEdit', 'linkRemove'],
    linkInsertButtons: ['linkBack'],
    linkConvertEmailAddress: false,
    quickInsertEnabled: false,
    pasteDeniedAttrs: ['id', 'style'],
    toolbarButtons: [
        'bold',
        'italic',
        'underline',
        'paragraphFormat',
        'formatOL',
        'formatUL',
        'outdent',
        'indent',
        'alignLeft',
        'alignCenter',
        'alignRight',
        'html',
        'undo',
        'redo'
    ],
    paragraphFormat: {
        N: 'Paragraph',
        H1: 'Heading 1',
        H2: 'Heading 2',
        H3: 'Heading 3',
        H4: 'Heading 4',
        H5: 'Heading 5',
        H6: 'Heading 6',
    },
    customPlugins: []
}
```

### Configuration example for a page with structured content

For example, the following configuration is applied by the system when editing structured content of pages on the _Content_ view under a website channel:

```json title="WEBSITE_STRUCTURED_CONTENT configuration"
{
  "imageDefaultWidth": 0,
  "imageResize": true,
  "imageUpload": false,
  "imagePaste": false,
  "imageDefaultMargin": null,
  "imageMove": true,
  "imageAddNewLine": false,
  "toolbarButtons": [
    "bold",
    "italic",
    "underline",
    "paragraphFormat",
    "formatOL",
    "formatUL",
    "outdent",
    "indent",
    "alignLeft",
    "alignCenter",
    "alignRight",
    "html",
    "insertLinkDropDown",
    "undo",
    "redo"
  ],
  "imageEditButtons": [ "imageReplace", "imageAlt", "imageAlign", "imageDisplay", "imageSize", "imageRemove" ],
  "customPlugins": [
    {
      "pluginName": "@kentico/xperience-admin-base/Link",
      "pluginOptions": {
        "dropdownOptions": [
          {
            "linkOption": "asset",
            "componentName": "@kentico/xperience-admin-base/AssetPanel"
          },
          {
            "linkOption": "external"
          },
          {
            "linkOption": "webpage",
            "componentName": "@kentico/xperience-admin-websites/PageLink"
          }
        ]
      }
    }
  ]
}
```

## Override and extend editor configurations dynamically

The system allows developers to exactly control which rich text editor configurations are loaded, and to make dynamic adjustments of the configuration content. This can be done by providing a custom implementation of the `IRichTextEditorConfigurationProvider` service. In most cases, we recommend extending the default implementation via the [decorator pattern](https://docs.kentico.com/documentation/developers-and-admins/customization/decorate-system-services.md).

See the following sections for examples of scenarios that use this customization pattern:

- [Replace editor configurations loaded by default](#replace-editor-configurations-loaded-by-default) – Set the system to automatically use a custom configuration for fields on the [page](https://docs.kentico.com/documentation/business-users/website-content.md) _Content_ view. The custom configuration then does not have to be selected manually when creating page content types.
- [Add custom CSS to the rich text editor](#add-custom-css-to-the-rich-text-editor) – Adjust the rich text editor appearance across the system by inserting custom CSS to all system rich text editor configurations.

### Replace editor configurations loaded by default

When adding fields with the _Rich text editor_ form component in the [field editor](https://docs.kentico.com/documentation/developers-and-admins/customization/field-editor.md), the selected **Configuration name** determines which options and plugins are available in the editor toolbar. If the user leaves the _Configuration name_ empty, the field uses a default editor configuration. The default configuration depends on the [admin UI location](#system-rich-text-editor-configurations) where the field will be used.

You can use the `IRichTextEditorConfigurationProvider` service to replace the configuration loaded by default with a [custom editor configuration](#define-editor-configurations) that is preferred for your project. With this change, users no longer need to select your custom configuration for every rich text field.

1. Open your Xperience solution in Visual Studio.

2. [Add a custom assembly](https://docs.kentico.com/documentation/developers-and-admins/customization/integrate-custom-code.md) (_Class Library_ project) with class discovery enabled to the solution, or re-use an existing assembly.

3. Create a new custom class in the assembly, and implement the `IRichTextEditorConfigurationProvider` interface.

4. Add the `GetConfigurationByName` method:
   - The `configurationName` parameter contains the identifier of the configuration that was requested. Write a condition to detect the configurations that you want to replace.
     - Access the constants in the `RichTextEditorConfigurationsIdentifiers` class to get the identifiers of the [system's configurations](#system-rich-text-editor-configurations).
     - If no configuration is assigned to the rich text editor fields outside of the specified locations, the `configurationName` is `null` and they the have the `DEFAULT` "empty" [configuration](#default-editor-configuration).

   - Use the [decorator customization pattern](https://docs.kentico.com/documentation/developers-and-admins/customization/decorate-system-services.md#decorate-services-via-dependency-injection) to call the default implementation for cases where you do not wish to replace the requested configuration.

5. Register the implementation using the `RegisterImplementation` assembly attribute.

The following example shows a custom implementation of `IRichTextEditorConfigurationProvider`. The implementation changes the configuration loaded for page fields on the _Content_ view.

```csharp title="Replacing the default rich text editor configuration for page fields"
using System;

using CMS;

using Kentico.Xperience.Admin.Base.Forms;
using Kentico.Xperience.Admin.Websites;

// Registers the custom IRichTextEditorConfigurationProvider implementation
[assembly: RegisterImplementation(typeof(IRichTextEditorConfigurationProvider), typeof(CustomDefaultRichTextEditorConfigurationProvider))]

public class CustomDefaultRichTextEditorConfigurationProvider : IRichTextEditorConfigurationProvider
{
    private readonly IRichTextEditorConfigurationProvider richTextEditorConfigurationProvider;
    
    public CustomDefaultRichTextEditorConfigurationProvider(IRichTextEditorConfigurationProvider richTextEditorConfigurationProvider)
    {
        // Gets an instance of the default IRichTextEditorConfigurationProvider service
        this.richTextEditorConfigurationProvider = richTextEditorConfigurationProvider;
    }
    
    // Loads the configuration for instances of the rich text editor in the administration
    public string GetConfigurationByName(string configurationName)
    {
        // The 'configurationName' parameter contains the identifier of the requested editor configuration
        // This condition replaces the system's default editor configuration for page fields
        if (string.Equals(configurationName, RichTextEditorConfigurationsIdentifiers.WEBSITE_STRUCTURED_CONTENT, StringComparison.OrdinalIgnoreCase))
        {
            // Use the identifier of your preferred custom configuration
            // For example, access the IDENTIFIER constant of the class used to register the configuration
            return richTextEditorConfigurationProvider.GetConfigurationByName(CustomDefaultEditorConfiguration.IDENTIFIER);
        }

        // Calls the default implementation and returns the unmodified configuration in all other cases
        return richTextEditorConfigurationProvider.GetConfigurationByName(configurationName);
    }
}
```

### Add custom CSS to the rich text editor

The following example demonstrates how to adjust the appearance and design of the rich text editor by inserting custom styles. The recommended approach is to create a [custom plugin](https://docs.kentico.com/documentation/developers-and-admins/configuration/rich-text-editor-configuration/rich-text-editor-plugins.md) containing the required elements and CSS, and then use the `IRichTextEditorConfigurationProvider` service to dynamically insert your plugin into the appropriate [editor configurations](#define-editor-configurations).

1. Create a custom [JavaScript module for the admin UI](https://docs.kentico.com/documentation/developers-and-admins/customization/extend-the-administration-interface/prepare-your-environment-for-admin-development.md).
   - Use the [client development boilerplate](https://docs.kentico.com/documentation/developers-and-admins/customization/extend-the-administration-interface/prepare-your-environment-for-admin-development.md#client-development-boilerplate) project to simplify the set up. Make sure the project has the **Kentico.Xperience.Admin** NuGet package installed so it can access admin UI-related APIs.

2. Extend the module's `webpack.config.js` to support CSS loading. For more information on configuring CSS loaders, see the [webpack documentation](https://webpack.js.org/loaders/#styling).
   ```js title="webpack.config.js"
   const projectConfig = {
       module: {
           rules: [
               ...
               // Adds the loader for basic CSS
               {
                   test: /\.css$/,
                   use: ["style-loader", "css-loader"],
               },
           ],
       },
    ...
   };
   ```

3. Within the module, create a React component file for the plugin.

   - Import any required styles. You do not need to return any custom markup.

   ```js title="CustomCSSRichTextEditorPlugin.tsx"
   import React from 'react';

   // Imports custom styles
   import './CustomCSSRichTextEditorPlugin.css';

   // The plugin component's name must have the 'RichTextEditorPlugin' suffix
   export const CustomCSSRichTextEditorPlugin = () => {
       return (
           // No markup to return
           <></>
       );
   };
   ```

4. Add files containing the styles that you wish to import.

   - You can use basic CSS, or any CSS extension language supported by your module's environment.

   ```css title="CustomCSSRichTextEditorPlugin.css"
   /* Examples of custom styles for the fr-view class, which is applied to the editor's content area */
   .fr-view h2 {
       font-size: 3em;
   }

   .fr-view {
       background-color: red;
   }
   ```

5. Export the plugin component from the module:
   ```tsx title="entry.tsx"
   export * from './path/CustomCSSRichTextEditorPlugin';
   ```

6. Create a class in the admin module, and implement the `IRichTextEditorConfigurationProvider` interface.

7. Add the `GetConfigurationByName` method and insert the `customPlugins` array with your custom CSS plugin into every configuration:

   ```csharp title="Adding the custom CSS plugin to rich text editor configurations"
   using System.Text.Json;
   using System.Text.Json.Nodes;

   using CMS;
   using Kentico.Xperience.Admin.Base.Forms;

   // Registers the custom IRichTextEditorConfigurationProvider implementation
   [assembly: RegisterImplementation(typeof(IRichTextEditorConfigurationProvider), typeof(CustomCssRichTextEditorConfigurationProvider))]

   public class CustomCssRichTextEditorConfigurationProvider : IRichTextEditorConfigurationProvider
   {
       private readonly IRichTextEditorConfigurationProvider richTextEditorConfigurationProvider;
       
       public CustomCssRichTextEditorConfigurationProvider(IRichTextEditorConfigurationProvider richTextEditorConfigurationProvider)
       {
           // Gets an instance of the default IRichTextEditorConfigurationProvider service
           this.richTextEditorConfigurationProvider = richTextEditorConfigurationProvider;
       }
       
       public string GetConfigurationByName(string configurationName)
       {
           // Gets the requested rich text editor configuration
           var configuration = richTextEditorConfigurationProvider.GetConfigurationByName(configurationName);
           
           // Adds the custom CSS plugin to the configuration's JSON content
           var jsonObj = JsonNode.Parse(configuration);
           if (jsonObj?["customPlugins"] is JsonArray optionsArray)
           {
               var newOption = new JsonObject
               {
                   // Replace 'orgName' and 'projectName' with the values for your client admin module.
                   // The final part of the plugin name must match the name of 
                   // the plugin's React component without the 'RichTextEditorPlugin' suffix.
                   ["pluginName"] = "@orgName/projectName/CustomCSS"
               };

               optionsArray.Add(newOption);
           }

           // Returns the modified configuration content, including the custom CSS plugin
           return jsonObj?.ToJsonString(new JsonSerializerOptions { WriteIndented = true });
       }
   }
   ```

   > **Note:** In the `pluginName` configuration value, replace `orgName` and `projectName` with your own values. By default, the boilerplate project uses `acme` and `web-admin` respectively. The final part of the plugin name must match the name of the plugin's React component without the _RichTextEditorPlugin_ suffix (_CustomCSS_ in this example).

The custom `IRichTextEditorConfigurationProvider` service dynamically inserts the custom CSS plugin into every rich text editor configuration, and the imported CSS is applied to the editor in the admin UI.
