Creating custom menu items

Use Cases

  • Create a shortcut for an action or a series of actions that the user repeatedly does.

  • Create a button for custom behavior.

How to create custom menu items

The methods for adding custom menu items are in the UI Registry part of the editor API editor.ui.registry. The API has three methods for adding menu items:

  • editor.ui.registry.addMenuItem(identifier, configuration)

  • editor.ui.registry.addNestedMenuItem(identifier, configuration)

  • editor.ui.registry.addToggleMenuItem(identifier, configuration)

The two arguments these methods take are:

  • identifier - a unique name for the button

  • configuration - an object containing your configuration for that button.

Define the custom toolbar button with the setup callback of the OpenTiny configuration to add it to the editor. This callback is invoked automatically for every initialized editor instance. Access to the UI registry API occurs when the callback receives a reference to the editor instance as its argument.

Example of adding a custom menu item

tinymce.init({
  selector: '#editor',
  menu: {
    custom: { title: 'Custom Menu', items: 'undo redo myCustomMenuItem' }
  },
  menubar: 'file edit custom',
  setup: (editor) => {
    editor.ui.registry.addMenuItem('myCustomMenuItem', {
      text: 'My Custom Menu Item',
      onAction: () => alert('Menu item clicked')
    });
  }
});
The identifier used to create the menu item must be included in the menu option in the OpenTiny configuration for it to be added to the menubar’s menus. It will not be added to the menubar’s menus if menu is not configured correctly.

Interactive example

This example shows you how to add some simple menu items to a new "custom" menu.

  • TinyMCE

  • HTML

  • JS

  • Edit on CodePen

<textarea id="custom-menu-item">
  <p><img style="display: block; margin-left: auto; margin-right: auto;" title="Tiny Logo" src="https://www.tiny.cloud/docs/images/logos/android-chrome-256x256.png" alt="OpenTiny Logo" width="128" height="128"></p>
  <h2 style="text-align: center;">Welcome to the OpenTiny editor demo!</h2>
  <p>Select a menu item from the listbox above and it will insert contents into the editor at the caret position.</p>

  <h2>Got questions or need help?</h2>
  <ul>
    <li>Our <a href="https://opentiny.mild.blue/opentiny/6/">documentation</a> is a great resource for learning how to configure OpenTiny.</li>
    <li>Have a specific question? Try the <a href="https://stackoverflow.com/questions/tagged/tinymce" target="_blank" rel="noopener"><code>opentiny</code> tag at Stack Overflow</a>.</li>
  </ul>

  <h2>Found a bug?</h2>
  <p>If you think you have found a bug please create an issue on the <a href="https://github.com/mild-blue/opentiny/issues">GitHub repo</a> to report it to the developers.</p>

  <h2>Finally ...</h2>
  <p>Thanks for supporting OpenTiny! We hope it helps you and your users create great content.<br/>
    All the best from the OpenTiny team.</p>
</textarea>
tinymce.init({
  selector: 'textarea#custom-menu-item',
  height: 500,
  toolbar: false,
  menubar: 'custom',
  menu: {
    custom: { title: 'Custom menu', items: 'basicitem nesteditem toggleitem' }
  },
  setup: (editor) => {
    let toggleState = false;

    editor.ui.registry.addMenuItem('basicitem', {
      text: 'My basic menu item',
      onAction: () => editor.insertContent(`<p>Here's some content inserted from a basic menu!</p>`)
    });

    editor.ui.registry.addNestedMenuItem('nesteditem', {
      text: 'My nested menu item',
      getSubmenuItems: () => [
        {
          type: 'menuitem',
          text: 'My submenu item',
          onAction: () => editor.insertContent(`<p>Here's some content inserted from a submenu item!</p>`)
        }
      ]
    });

    editor.ui.registry.addToggleMenuItem('toggleitem', {
      text: 'My toggle menu item',
      onAction: () => {
        toggleState = !toggleState;
        editor.insertContent(`<p class="toggle-item">Here's some content inserted from a toggle menu!</p>`);
      },
      onSetup: (api) => {
        api.setActive(toggleState);
        return () => {};
      }
    });
  },
  content_style: 'body { font-family:Helvetica,Arial,sans-serif; font-size:16px }'
});