Mention Support in EJ2 JavaScript Markdown Editor Control

16 May 202522 minutes to read

By integrating the Mention control with the Markdown Editor, users can effortlessly mention or tag other users or objects from a suggested list. This eliminates the need to manually type out names or identifying information, improving both efficiency and accuracy.

Enabling Mention in EJ2 JavaScript Markdown Editor

To enable the Mention functionality within the Markdown Editor, set the target property of the Mention control to the ID of the textarea element inside the editor. When specifying the target, ensure that you append the suffix _editable-content to the ID. This configuration allows users to mention or tag others from the suggested list while editing text.

When a user types the @ symbol followed by a character, the Markdown Editor displays a list of suggestions. Users can select an item from the list by either clicking on it or typing the desired name.

Configuring Mention Properties

The Syncfusion Mention control provides several customizable properties to enhance the tagging experience:

  • allowSpaces - Allow to continue search action if user enter space after mention character while searching.
  • suggestionCount - Defines the maximum number of items displayed in the suggestion list.
  • itemTemplate - Customizes the appearance of items in the suggestion list.

Example: Implementing Mention in Markdown Editor

The following example demonstrates how to enable Mention support in the Markdown Editor.

ej.base.enableRipple(true);

var textArea;
var mdsource;
var htmlPreview;

var markdownMention = new ej.richtexteditor.RichTextEditor({
  value: `Hello [@Maria](mailto:maria@gmail.com)\n\nWelcome to the mention integration with markdown editor demo. Type @ character and tag user from the suggestion list.`,
  height: 250,
  editorMode: 'Markdown',
  toolbarSettings: {
    items: [
      'Bold',
      'Italic',
      'StrikeThrough',
      '|',
      'Formats',
      'Blockquote',
      'OrderedList',
      'UnorderedList',
      'SuperScript',
      'SubScript',
      '|',
      'CreateLink',
      'Image',
      'CreateTable',
      '|',

      {
        tooltipText: 'Preview',
        template:
          '<button id="preview-code" class="e-tbar-btn e-control e-btn e-icon-btn"  aria-label="Preview Code">' +
          '<span class="e-btn-icon e-md-preview e-icons"></span></button>',
      },
      '|',
      'Undo',
      'Redo',
    ],
  },
  created: function () {
    textArea = markdownMention.contentModule.getEditPanel();
    textArea.addEventListener('keyup', function (e) {
      markdownConversion();
    });
    mdsource = document.getElementById('preview-code');
    mdsource.addEventListener('click', function (e) {
      fullPreview();
      if (e.currentTarget.classList.contains('e-active')) {
        markdownMention.disableToolbarItem([
          'Bold',
          'Italic',
          'StrikeThrough',
          'OrderedList',
          'UnorderedList',
          'SuperScript',
          'SubScript',
          'CreateLink',
          'Image',
          'CreateTable',
          'Formats',
          'Blockquote',
          'Undo',
          'Redo',
        ]);
      } else {
        markdownMention.enableToolbarItem([
          'Bold',
          'Italic',
          'StrikeThrough',
          'OrderedList',
          'UnorderedList',
          'SuperScript',
          'SubScript',
          'CreateLink',
          'Image',
          'CreateTable',
          'Formats',
          'Blockquote',
          'Undo',
          'Redo',
        ]);
      }
    });
  },
});
markdownMention.appendTo('#markdownMention');

var emailData = [
  {
    name: 'Selma Rose',
    initial: 'SR',
    email: 'selma@gmail.com',
    color: '#FAFDFF',
    bgColor: '#01579B',
  },
  {
    name: 'Maria',
    initial: 'MA',
    email: 'maria@gmail.com',
    color: '#004378',
    bgColor: '#ADDBFF',
  },
  {
    name: 'Russo Kay',
    initial: 'RK',
    email: 'russo@gmail.com',
    color: '#F9DEDC',
    bgColor: '#8C1D18',
  },
  {
    name: 'Robert',
    initial: 'RO',
    email: 'robert@gmail.com',
    color: '#FFD6F7',
    bgColor: '#37003A',
  },
  {
    name: 'Camden Kate',
    initial: 'CK',
    email: 'camden@gmail.com',
    color: '#FFFFFF',
    bgColor: '#464ECF',
  },
  {
    name: 'Garth',
    initial: 'GA',
    email: 'garth@gmail.com',
    color: '#FFFFFF',
    bgColor: '#008861',
  },
  {
    name: 'Andrew James',
    initial: 'AJ',
    email: 'james@gmail.com',
    color: '#FFFFFF',
    bgColor: '#53CA17',
  },
  {
    name: 'Olivia',
    initial: 'OL',
    email: 'olivia@gmail.com',
    color: '#FFFFFF',
    bgColor: '#8C1D18',
  },
  {
    name: 'Sophia',
    initial: 'SO',
    email: 'sophia@gmail.com',
    color: '#000000',
    bgColor: '#D0BCFF',
  },
  {
    name: 'Margaret',
    initial: 'MA',
    email: 'margaret@gmail.com',
    color: '#000000',
    bgColor: '#F2B8B5',
  },
  {
    name: 'Ursula Ann',
    initial: 'UA',
    email: 'ursula@gmail.com',
    color: '#000000',
    bgColor: '#47ACFB',
  },
  {
    name: 'Laura Grace',
    initial: 'LG',
    email: 'laura@gmail.com',
    color: '#000000',
    bgColor: '#FFE088',
  },
  {
    name: 'Albert',
    initial: 'AL',
    email: 'albert@gmail.com',
    color: '#FFFFFF',
    bgColor: '#00335B',
  },
  {
    name: 'William',
    initial: 'WA',
    email: 'william@gmail.com',
    color: '#FFFFFF',
    bgColor: '#163E02',
  },
];
var mention = new ej.dropdowns.Mention({
  dataSource: emailData,
  fields: { text: 'name' },
  displayTemplate: '[@${name}](mailto:${email})',
  itemTemplate:
    '<div class="editor-mention-item-template"><div class="em-header"><div class="em-avatar" style="background-color: ${bgColor}; color: ${color}"><div class="em-initial">${initial}</div></div></div><div class="em-content"><div class="em-name">${name}</div><div class="em-email">${email}</div></div></div>',
  popupWidth: '250px',
  popupHeight: '200px',
  sortOrder: 'Ascending',
  target: markdownMention.inputElement,
  allowSpaces: true,
});
mention.appendTo('#editorMention');

function markdownConversion() {
  if (mdsource.classList.contains('e-active')) {
    var id = markdownMention.getID() + 'html-view';
    var htmlPreview = document.body.querySelector(
      '#markdownMentionhtml-preview'
    );
    htmlPreview.innerHTML = marked(
      markdownMention.contentModule.getEditPanel().value
    );
  }
}
function fullPreview() {
  var id = markdownMention.getID() + 'html-preview';
  var htmlPreview = markdownMention.element.querySelector('#' + id);
  var previewTextArea = markdownMention.element.querySelector('.e-rte-content');
  if (mdsource.classList.contains('e-active')) {
    mdsource.classList.remove('e-active');
    mdsource.parentElement.title = 'Preview';
    textArea.style.display = 'block';
    htmlPreview.style.display = 'none';
    previewTextArea.style.overflow = 'hidden';
  } else {
    mdsource.classList.add('e-active');
    if (!htmlPreview) {
      htmlPreview = ej.base.createElement('div', {
        className: 'e-content e-pre-source',
      });
      htmlPreview.id = id;
      textArea.parentNode.appendChild(htmlPreview);
      previewTextArea.style.overflow = 'auto';
    }
    if (previewTextArea.style.overflow === 'hidden') {
      previewTextArea.style.overflow = 'auto';
    }
    textArea.style.display = 'none';
    htmlPreview.style.display = 'block';
    htmlPreview.innerHTML = marked(
      markdownMention.contentModule.getEditPanel().value
    );
    mdsource.parentElement.title = 'Code View';
  }
}

loadExternalFile();
// Dynamically load the marked.js file
function loadExternalFile() {
  var script = document.createElement('script');
  script.src = 'https://cdnjs.cloudflare.com/ajax/libs/marked/0.3.19/marked.js';
  document.getElementsByTagName('head')[0].appendChild(script);
}
<!DOCTYPE html><html lang="en"><head>
    <title>Essential JS 2 Rich Text Editor</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="description" content="Typescript UI Controls">
    <meta name="author" content="Syncfusion">
    <link href="index.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/30.1.37/ej2-base/styles/material.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/30.1.37/ej2-richtexteditor/styles/material.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/30.1.37/ej2-inputs/styles/material.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/30.1.37/ej2-lists/styles/material.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/30.1.37/ej2-navigations/styles/material.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/30.1.37/ej2-popups/styles/material.css" rel="stylesheet">
     <link href="https://cdn.syncfusion.com/ej2/30.1.37/ej2-buttons/styles/material.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/30.1.37/ej2-splitbuttons/styles/material.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/30.1.37/ej2-dropdowns/styles/material.css" rel="stylesheet"/>
    
   
<script src="https://cdn.syncfusion.com/ej2/30.1.37/dist/ej2.min.js" type="text/javascript"></script>
<script src="https://cdn.syncfusion.com/ej2/syncfusion-helper.js" type ="text/javascript"></script>
</head>

<body>
    
    <div id="container">
        <div id="editorMention"></div>
        <div id="markdownMention"> 
    </div>
    <style>
        .e-richtexteditor textarea.e-content {
            float: left;
        }
        .e-richtexteditor .e-rte-content {
            overflow: hidden;
        }
        .e-icon-btn.e-active .e-md-preview::before {
            content: '\e350';
        }
        .e-icon-btn .e-md-preview::before {
            content: '\e345';
        }
            .bootstrap4 .e-icon-btn.e-active .e-md-preview::before {
            content: '\e790';
        }

        .bootstrap4 .e-icon-btn .e-md-preview::before {
            content: '\e787';
        }

        .tailwind .e-icon-btn.e-active .e-md-preview::before,
        .tailwind-dark .e-icon-btn.e-active .e-md-preview::before,
        .tailwind3 .e-icon-btn.e-active .e-md-preview::before,
        .tailwind3-dark .e-icon-btn.e-active .e-md-preview::before,
        .fluent .e-icon-btn.e-active .e-md-preview::before,
        .fluent-dark .e-icon-btn.e-active .e-md-preview::before,
        .fluent2 .e-icon-btn.e-active .e-md-preview::before,
        .fluent2-dark .e-icon-btn.e-active .e-md-preview::before,
        .fluent2-highcontrast .e-icon-btn.e-active .e-md-preview::before,
        .bootstrap5 .e-icon-btn.e-active .e-md-preview::before,
        .bootstrap5-dark .e-icon-btn.e-active .e-md-preview::before,
        .material3 .e-icon-btn.e-active .e-md-preview::before,
        .material3-dark .e-icon-btn.e-active .e-md-preview::before {
            content: '\e80e';
        }

        .tailwind .e-icon-btn .e-md-preview::before,
        .tailwind-dark .e-icon-btn .e-md-preview::before,
        .tailwind3 .e-icon-btn .e-md-preview::before,
        .tailwind3-dark .e-icon-btn .e-md-preview::before,
        .bootstrap5 .e-icon-btn .e-md-preview::before,
        .bootstrap5-dark .e-icon-btn .e-md-preview::before,
        .fluent .e-icon-btn .e-md-preview::before,
        .fluent-dark .e-icon-btn .e-md-preview::before,
        .fluent2 .e-icon-btn .e-md-preview::before,
        .fluent2-dark .e-icon-btn .e-md-preview::before,
        .fluent2-highcontrast .e-icon-btn .e-md-preview::before,
        .material3 .e-icon-btn .e-md-preview::before,
        .material3-dark .e-icon-btn .e-md-preview::before {
            content: '\e7de';
        }

        .editor-mention-item-template {
            width: 100%;
            height: 100%;
            display: flex;
            flex-direction: row;
            align-items: center;
        }

        .em-content {
            display: flex;
            flex-direction: column;
            justify-content: center;
        }

        .em-avatar {
            width: 32px;
            height: 32px;
            text-align: center;
            border-radius: 50%;
            font-size: 12px;
            font-weight: 500;
            text-indent: 0px;
            line-height: 13px;
            color: #fff;
            display: flex;
            align-items: center;
            justify-content: center;
        }

        .em-name {
            color: rgb(16, 24, 40);
            font-size: 14px;
            font-weight: 400;
            line-height: 14px;
            margin-bottom: 5px;
        }

        .em-email {
            color: gray;
            font-size: 12px;
            font-weight: 400;
            line-height: 14px;
        }

        #markdownMention_editable-content_popup li {
            padding: 10px;
            height: 60px;
        }

        body[class*="-dark"] .em-name {
            color: #fff !important;
        }

    </style>


<script>
var ele = document.getElementById('container');
if(ele) {
  ele.style.visibility = "visible";
}   
      </script>
<script src="index.js" type="text/javascript"></script>
</body></html>