In almost all of the text editors available for React JS adding your own dropdown list is not an easy task. In a React app I was using suneditor, and I needed to add my own dropdown list for the users to select a merge tag from, but I could not find a way from their documentation. The only option was to use their custom plugin.
From suneditor’s documentation on custom plugin, I found a way to add my own list. Here’s how it can be done in two steps.
Add A Custom Plugin Code
Copy and paste the below code in a separate file, with changes such as file and plugin names. I’m naming the file merge_tag_plugin.js
and the plugin namemerge_tag
. Export this. (Alternatively, you can use it at the same place you’re using suneditor)
const mergeTag = {
// @Required
// plugin name
name: 'merge_tag',
// @Required
// data display
display: 'submenu',
// @Required
// add function - It is called only once when the plugin is first run.
// This function generates HTML to append and register the event.
// arguments - (core : core object, targetElement : clicked button element)
add: function (core, targetElement) {
// Generate submenu HTML
// Always bind "core" when calling a plugin function
let listDiv = this.setSubmenu.call(core);
// You must bind "core" object when registering an event.
/** add event listeners */
var self = this;
listDiv.querySelectorAll('.se-btn-list').forEach(function (btn) {
btn.addEventListener('click', self.onClick.bind(core));
});
// @Required
// You must add the "submenu" element using the "core.initMenuTarget" method.
/** append target button menu */
core.initMenuTarget(this.name, targetElement, listDiv);
},
setSubmenu: function () {
const listDiv = this.util.createElement('DIV');
// @Required
// A "se-submenu" class is required for the top level element.
listDiv.className = 'se-submenu se-list-layer';
listDiv.innerHTML = '<div class="se-list-inner se-list-font-size"><ul class="se-list-basic"><li><button type="button" class="se-btn-list" value="{firstName}">{firstName}</button></li><li><button type="button" class="se-btn-list" value="{lastName}">{lastName}</button></li></ul></div>'
return listDiv;
},
onClick: function (e) {
const value = e.target.value;
const node = this.util.createElement('span');
this.util.addClass(node, 'se-custom-tag');
node.textContent = value;
this.insertNode(node);
const zeroWidthSpace = this.util.createTextNode(this.util.zeroWidthSpace);
node.parentNode.insertBefore(zeroWidthSpace, node.nextSibling);
this.submenuOff();
}
};
export default mergeTag
Notice setSubmenu
method. It’s there in lastDiv.innerHTML
we’re giving the our list of merge tags ({firstName} and {lastName}).
Pass Custom Plugin Name In setOptions
Import the plugin into the file where you’re using suneditor and pass it along the setOptions plugins as shown below.
import mergeTag from "../../merge-tag-plugin";
//...
<SunEditor
onChange={handleInputChange}
placeholder={"Insert Text Here"}
showToolbar={true}
setOptions={{
height: 200,
plugins: [
mergeTag
//...
]
}} />
Pass Custom Object setOptions buttonList
This object will link up our custom plugin code based on the name we used (merge_tag
). Also, the innerHTML
is what will show as the name of the dropdown click.
<SunEditor
onChange={handleInputChange}
placeholder={"Insert Text Here"}
showToolbar={true}
setOptions={{
height: 200,
plugins: [
mergeTag
],
buttonList: [
{
name: 'merge_tag',
dataCommand: 'merge_tag',
buttonClass: '',
title: 'Merge Tag',
dataDisplay: 'submenu',
innerHTML: '<span>Merge Tag</span>',
}
//...
],
]
}} />
And it’s done! The editor will look and behave something like this:
(Note that you might need to import and add default plugins and also provide additional buttonList items for all of the toolbar to appear beside the custom plugin.)