Language
Category
Search

TinyMCE: wrap selected text in the editor with a span element

Configure a button to wrap selected text in the editor with a span element containing a specific class with custom styles

At JavaScript By Rudi Drusian Lange
Published on
Last updated

The idea is to configure a button to toggle between adding and removing a span with a css style to the selected text.

This article used the latest version of series 5, TinyMCE 5.10.9 and also the last version available at this date of series 6, TinyMCE 6.8.2.

Demo e Download

The content covered in this article can be tested online in our demo and can also be downloaded for local use.

Demo Download

Basic configuration

Create the <textarea> and load TinyMCE:

HTML

<textarea id='default'></textarea>
<script src='tinymce.5.10.9/js/tinymce/tinymce.min.js'></script>

Change the path to the tinymce.min.js file according to your installation.

Initializing

We will start with a basic editor using the textarea element with id='default' created above. The height will be set to 500px and the plugin code will be loaded to make the source code available in HTML. The toolbar will be customized containing bold, italic and code buttons.

JavaScript

tinymce.init({
  selector: 'textarea#default',
  height: 500,
  plugins: 'code',
  toolbar: 'bold italic code',
  content_css: 'css/style.css?1',
  formats: {
     bold: {
        inline: 'span',
        attributes: { class: 'text-bold' },
	   },
	},
});

The content_css option configures the path to the css file containing the style rules that will be used within the editor, for example to customize fonts, paragraphs and headers. The characters ?1 in front of the css file name are used to clear the cache after changes, changing the number in front of the question mark forces the file to be reloaded, this occurs because it is understood that the name is different but the file being loaded is the same.

Finally, we changed the default behavior of bold which is to wrap the selected text in a <b> element. With the configuration above, when applying bold the selected text will be wrapped in a <span class='text-bold'> element. In this case it is necessary to style the bold using the text-bold class in the css file.

CSS

.text-bold {
   font-weight: bold;
}

Test the bold button by inspecting the editor's html code using the < > button.

Configuring the buttons

Starting with CSS, prepare the classes that will be used in the editor.

CSS

.text-bold { font-weight: bold; }
.text-red { color: red; }
.text-blue { color: blue; }

Remember to change the number at the end of style.css?1 if you make any changes to the css after loading the editor. TinyMCE stores cache of the css file and only by simulating another name the changes will take effect.

Below is the complete code with two additional buttons, Red and Blue, which wrap the selected text in a span containing their respective css classes.

JavaScript

// Function to replace HTML characters with their entities
function encodeHTML(s) {
   return s.replace(/&/g, '&amp;')
           .replace(/</g, '&lt;')
           .replace(/>/g, '&gt;')
           .replace(/"/g, '&quot;');
}

tinymce.init({
  selector: 'textarea#default',
  height: 500,
  plugins: 'code',
  // Adds Red and Blue buttons to the toolbar
  toolbar: 'bold italic code | textred textblue',
  content_css: 'css/style.css?1',
  formats: {
    bold: {
       inline: 'span',
       attributes: { class: 'text-bold' },
		},
    // Creates the format for the buttons
   'textred': {   inline: 'span',   classes: 'text-red',   wrapper: true   },   'textblue': {   inline: 'span',   classes: 'text-blue',     wrapper: true   }, }, setup: function(editor) {   // Function to wrap selected text with span // Receives as parameter the class to be used in the span
  function wrapText(cls) {   const node = editor.selection.getNode();     const selectedText = encodeHTML(editor.selection.getContent({ format: 'text' }));   if (node.nodeName == 'SPAN') {     const l = node.classList.length;     if (l == 0) { node.classList.add(cls); } else if (l == 1) {     if (node.classList.contains(cls)) { editor.execCommand('mceReplaceContent', false, selectedText); } else { node.classList.add(cls); } } else { node.classList.remove(cls); } } else { editor.execCommand( 'mceReplaceContent', false, '<span class="' + cls + '">' + selectedText + '</span>'
);         } }   // Configure the buttons  editor.ui.registry.addButton('textred', {   text: 'Red',     tooltip: 'Red span',     onAction: function() {     wrapText('text-red'); } }); editor.ui.registry.addButton('textblue', {   text: 'Blue',   onAction: function() {     wrapText('text-blue'); } }); } });

In this example, two additional buttons are configured to style the text in the editor using a span element containing a css class. Select the text and click the new buttons to toggle customization.

To remove customization, the selection must contain exactly the same text as the original selection, including white space. To toggle customization it is necessary to change the cursor position in the editor before selecting the text again, see more information in the bugs section below.

Final considerations

The wrapText() function wraps the selected text in a span if it is not already in one. If the text is already wrapped and it does not have the class linked to the button, the class will be added to the span instead of adding a new span.

When clicking the button, if the span involving the text has more than one class, one of them being the class linked to the button, this will be removed and the span will be preserved with the rest of its classes.

The span will not be added if the cursor is positioned on the word and the text is not selected.

This article serves as inspiration for other situations, you can wrap text in a div, create buttons to add templates, use creativity.

This is just an example with simple functionality, a starting point for further customization. Therefore, the wrapText() function does not have all the necessary logic to avoid failures. In some situations the buttons will not work as expected.

Bugs

A bug that appears to be related to the editor occurs as follows: When selecting text and clicking the bold button the pattern is applied, if you click immediately after in the Red button the text will turn red and lose its boldness. To work as it should, after clicking the bold button, change the cursor position, select the text again and only then click the Red button, so the text will be in bold red.

This same error occurs when using only the new buttons. If something doesn't work, try changing the cursor position and selecting the text again. If it's just one word, double clicking works. Moving the keyboard cursor back and forth and selecting again also works.

Sources

The content of this article was written by consulting the documentation on the TinyMCE website, topics on the stackoverflow website, and questions asked to ChatGPT.

This is not my original language and I don't speak it very well. I used my little knowledge and translators tools to compose the text of this article. Sorry for possible spelling or grammatical errors, suggestions for corrections are appreciated and can be sent to the contact email in the footer of the site. My intention is to share some knowledge and I hope this translation is good enough.