Custom Rich Text Editor (RTE) Plugins for Adobe Experience Manager

January 06, 2022

Out-of-the-box (OOTB) plugins and their features cover many text editing use cases, but there will always be a need for customization. Recently, I came across a requirement where authors wanted the flexibility to add data attributes to the HTML elements for analytics tracking using the Text component RTE capabilities in Adobe Experience Manager (AEM).

Learn how to add a custom tool to RTE that will add data attributes to a specific element within HTML by following the steps outlined in this article. This same process can be used for any other custom RTE Tools you have to add as well.

By following these steps, you will enable the author to add attributes or remove attributes using the in-place editing toolbar in AEM, as can be seen below.

text big image block

How to Add a Custom Plugin to RTE?

Adding a new plugin to RTE is a five-step process and involves JavaScript coding.

  1. Create a new Clientlib and provide Categories
  2. Create a new Command and Register it with CommandRegistry
  3. Create a new Plugin and Register it with PluginRegistry
  4. Create a custom dialog if there is a need
  5. Enable plugin
Step 1: Create a New Clientlib and Provide Categories

The clientlib name required to load the custom RTE plugin in AEM Author editing mode is rte.coralui3.

Create a clientlib directory and set the categories to rte.coralui3:

Sample code:

<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:cq="" xmlns:jcr=""
Step 2: Create and Register Command

There is a predefined interface to create the RTE commands; each command must extend this and write implementation:

Interface: CUI.rte.commands.Command

Create the custom command and Register it with CommandRegistry that manages the commands for rich text editing.

Sample Command code:

CUI.rte.commands.SampleCommand = new Class({

   extend: CUI.rte.commands.Command,

   toString: 'SampleCommand',

   isCommand: function (cmdStr) {
       return (cmdStr === 'command_name');

   getProcessingOptions: function () {
       var cmd = CUI.rte.commands.Command;
       return cmd.PO_SELECTION | cmd.PO_BOOKMARK | cmd.PO_NODELIST;

   execute: function (execDef) {
       // add implementation

// register command with CommandRegistry
CUI.rte.commands.CommandRegistry.register('command_name', CUI.rte.commands.SampleCommand);
Step 3: Create and Register Plugin

Like Command interface, there is a predefined Plugin interface and each plugin must extend and write implementations.

Interface: CUI.rte.plugins.Plugin

Create the custom Plugin and Register it with PluginRegistry that manages the plugins.

CUI.rte.plugins.SamplePlugin = new Class(

   extend: CUI.rte.plugins.Plugin,

   features: null,

   pluginId: SamplePlugin,

   config: {...},
   // write implementation
   getFeatures: function () {return [];},
   // write implementation
   initializeUI: function (tbGenerator, options) {},
   // write implementation
   execute: function (pluginCommand, value, envOptions) {},
   // write implementation
   updateState: function (selDef) {},

   getTooltip: function (command) {
       return (this.config.tooltips ? this.config.tooltips[command] : null);


// register plugin
CUI.rte.plugins.PluginRegistry.register('sample_plugin', CUI.rte.plugins.SamplePlugin);
Step 4: Plugin Dialog

If there is a user input needed for the plugin or its features, there are two ways to create the Plugin Dialog.

  1. Extend the DefaultDialog and add fields CUI.rte.ui.cui.DefaultDialog
  2. Create a custom dialog
CUI.rte.ui.cui.SampleDialog = new Class({

 extend: CUI.rte.ui.cui.AbstractDialog,

 initialize: function(config) {
   this.config = config;
   this.context = this.editorKernel.getEditContext();

 onShow: function() {...},

 onHide: function() {...},

 preprocessModel: function () {
   // this method may be overridden by implementing dialogs to pre-process before passing it to other methods

 dlgFromModel: function () {
   // this method may be overridden by implementing dialogs to transfer basic data from model to view

 validate: function () {
   // run validations
   return true;

 dlgToModel: function () {
   // this method may be overridden by implementing dialogs to transfer basic data from view to model

 postprocessModel: function () {
   // this method may be overridden by implementing dialogs to post-process


Note: There is a Helper class available which has some useful methods when instantiating the dialog - Class: CUI.rte.ui.DialogHelper

Step 5: Add plugin to RTE

Based on the requirement, add the plugin and its features configuration to RTE for content editing.

Enable the RTE Plugin features

Add the following code to the rtePlugins node inside the dialog and for inplaceEditing.

Dialog rtePlugins Location <dialog-richtext-field>/rtePlugins
InplaceEditing rtePlugins Location <component>/cq:editConfig/cq:inplaceEditing/inplaceEditingConfig/rtePlugins


Configure Editor Toolbar

There are four supported types of RTE editors and configurations for them explained in the below table. Add the plugin and feature to the toolbar list.

Format: plugin_name#feature_name

Editor Type Config Location Property
Dialog Inline <dialog-richtext-field>/uiSettings/cui/inline toolbar
Dialog fullscreen <dialog-richtext-field>/uiSettings/cui/dialogFullScreen toolbar
Inplace editor <component>/cq:editConfig/cq:inplaceEditing/inplaceEditingConfig/uiSettings/cui/inline toolbar
Inplace editor fullscreen <component>/cq:editConfig/cq:inplaceEditing/inplaceEditingConfig/uiSettings/cui/fullscreen toolbar


Reference: There is an OOTB rich text clientlib that has the definitions, helper classes, and OOTB Plugins, features, and Commands. Path to the library on your local AEM environment.

While OOTB plugins cover most scenarios for text editing, the above custom tools allow for data attributes to be added to a specific element within HTML in Adobe Experience Manager. Download the example package below to see the functionality of adding and removing attributes. 

Glossary of Terms

  • RTE - Rich Text Editor
  • Command - This performs the action that the plugin passes to   
  • CommandRegistry - Registry that holds all the RTE Commands  
  • Dialog – It is a Plugin Dialog, which provides the input forms for user inputs and DOM management. 
  • Plugin – Identifiable with a unique name and consists of 1 or more features for editing   
  • PluginRegistry - Registry which manages all the RTE plugins