Creating custom Split toolbar buttons

A split button contains a basic button and a menu button, wrapped up into one toolbar item. Clicking the menu button section opens a dropdown list. The basic button section and the menu items can be configured to trigger different actions when clicked.

Options

Name Value Target component Requirement Description

text

string

Primary button

optional

Text displayed if no icon is found.

icon

string

Primary button

optional

Name of the icon to be displayed. Must correspond to an icon: in the icon pack, in a custom icon pack, or added using the addIcon API.

onAction

(api) => void

Primary button

required

Function invoked when the basic button section is clicked.

select

(value: string) => boolean

Choice menu items

optional

default: false - Function run on each option when the menu is opened to determine if it should be highlighted as active.

columns

number or 'auto'

Drop-down menu

optional

default: 1 - Number of columns for the list of options. When set to more than 1 column, only the icon for each item will be shown.

fetch

(success: (menu) => void) => void

Drop-down menu

required

A callback function that should be passed a list of choice menu items for the dropdown menu.

onItemAction

(api, value) => void

Choice menu items

required

Function invoked when a dropdown list option is clicked. The value is passed from the selected choice menu item.

onSetup

(api) => (api) => void

All

optional

default: () => () => {} - Function invoked when the button is rendered. For details, see: Using onSetup.

API

Name Value Description

isEnabled

() => boolean

Checks if the button is enabled.

setEnabled

(state: boolean) => void

Sets the button’s enabled state.

isActive

() => boolean

Checks the button’s toggle state.

setActive

(state: boolean) => void

Sets the button’s toggle state.

Split button example and explanation

The following example sets up a split button with a text label and a static dropdown menu.

  • TinyMCE

  • HTML

  • JS

  • Edit on CodePen

<textarea id="custom-toolbar-split-button">
  <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="TinyMCE Logo" width="128" height="128"></p>
  <h2 style="text-align: center;">Welcome to the TinyMCE 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://www.tiny.cloud/docs/tinymce/6/">documentation</a> is a great resource for learning how to configure TinyMCE.</li>
    <li>Have a specific question? Try the <a href="https://stackoverflow.com/questions/tagged/tinymce" target="_blank" rel="noopener"><code>tinymce</code> tag at Stack Overflow</a>.</li>
    <li>We also offer enterprise grade support as part of <a href="https://www.tiny.cloud/pricing">TinyMCE premium plans</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/tinymce/tinymce/issues">GitHub repo</a> to report it to the developers.</p>

  <h2>Finally ...</h2>
  <p>Don't forget to check out our other product <a href="http://www.plupload.com" target="_blank">Plupload</a>, your ultimate upload solution featuring HTML5 upload support.</p>
  <p>Thanks for supporting TinyMCE! We hope it helps you and your users create great content.
    <br>All the best from the TinyMCE team.</p>
</textarea>
tinymce.init({
  selector: 'textarea#custom-toolbar-split-button',
  toolbar: 'myButton',
  menubar: false,
  setup: (editor) => {
    editor.ui.registry.addSplitButton('myButton', {
      text: 'My Button',
      icon: 'info',
      tooltip: 'This is an example split-button',
      onAction: () => editor.insertContent('<p>You clicked the main button</p>'),
      onItemAction: (api, value) => editor.insertContent(value),
      fetch: (callback) => {
        const items = [
          {
            type: 'choiceitem',
            icon: 'notice',
            text: 'Menu item 1',
            value: '&nbsp;<em>You clicked menu item 1!</em>'
          },
          {
            type: 'choiceitem',
            icon: 'warning',
            text: 'Menu item 2',
            value: '&nbsp;<em>You clicked menu item 2!</em>'
          }
        ];
        callback(items);
      }
    });
  },
  content_style: 'body { font-family:Helvetica,Arial,sans-serif; font-size:16px }'
});

A split button is similar to a basic button in that they both require an onAction callback. The onAction callback function should take the button’s API and return nothing. It is called when the basic button section is clicked. In this example, onAction calls editor.insertContent(value) which inserts the given content into the editor.

onItemAction is called when a menu item is clicked. The callback function is passed the split button’s API and the value of the selected menu item. Nothing should be returned. The example calls editor.insertContent(value) to insert the value into the editor’s content.

The fetch function is called whenever the split button’s drop-down menu is opened. It is a function that takes a callback and passes it an array of menu items to be rendered in the button’s drop-down menu. This allows for asynchronous fetching of the menu items.

Choice menu items

Choice menu items are a special type of menu item used for split toolbar button menu items. For information on split buttons, see: Split toolbar buttons.

Options

Name Value Requirement Description

value

any

required

A value that is passed to onItemAction when the choice menu item is clicked.

text

string

optional

Text to display.

icon

string

optional

Name of the icon to be displayed. Must correspond to an icon: in the icon pack, in a custom icon pack, or added using the addIcon API.

enabled

boolean

optional

default: true - Represents the menu item’s state. When false, the menu item is unclickable. Toggled by the menu item’s API.

shortcut

string

optional

Text to display in the shortcut label. To register a shortcut, see: Add custom shortcuts to TinyMCE.

For an example of how choice menu items are used in split toolbar buttons, see: Split button example and explanation.

Using onSetup

onSetup is a complex property. It takes a function that is passed the component’s API and should return a callback that is passed the component’s API and returns nothing. This occurs because onSetup runs whenever the component is rendered, and the returned callback is executed when the component is destroyed. This is essentially an onTeardown handler, and can be used to unbind events and callbacks.

To clarify, in code onSetup may look like this:

onSetup: (api) => {
  // Do something here on component render, like set component properties or bind an event listener

  return (api) => {
    // Do something here on teardown, like unbind an event listener
  };
};

To bind a callback function to an editor event use editor.on(eventName, callback). To unbind an event listener use editor.off(eventName, callback). Any event listeners should be unbound in the teardown callback. The only editor event which does not need to be unbound is init e.g. editor.on('init', callback).

  • The callback function for editor.off() should be the same function passed to editor.on(). For example, if a editorEventCallback function is bound to the NodeChange event when the button is created, onSetup should return (api) => editor.off('NodeChange', editorEventCallback).

  • If onSetup does not have any event listeners or only listens to the init event, onSetup can return an empty function e.g. return () => {};.