---
title: "Creating custom Toggle toolbar buttons"
description: "Creating custom Toggle toolbar buttons for TinyMCE"
canonical_url: "https://www.tiny.cloud/docs/tinymce/latest/custom-toggle-toolbar-button/"
md_url: "https://www.tiny.cloud/docs/tinymce/7/custom-toggle-toolbar-button/index.md"
version: "7"
last_updated: "2024-10-09T05:34:31Z"
tokens: 1946
---
Important This page documents TinyMCE 7. For new projects, Tiny recommends using the latest, most up-to-date version. [See TinyMCE 8 documentation](../../latest/custom-toggle-toolbar-button/).
# Creating custom Toggle toolbar buttons

A toggle button triggers an action when clicked but also has a concept of state. This means it can be toggled `on` and `off`. A toggle button gives the user visual feedback for its state through CSS styling. An example of this behavior is the **Bold** button that is highlighted when the cursor is in a word with bold formatting.

## Options

| Name | Value | Requirement | Description |
| --- | --- | --- | --- |
| text | string | optional | Text to display if no icon is found. |
| icon | string | optional | Name of the icon to be displayed. Must correspond to an icon: in the [icon pack](../editor-icon-identifiers/), in a [custom icon pack](../creating-an-icon-pack/), or added using the [`addIcon` API](../apis/tinymce.editor.ui.registry/#addIcon). |
| tooltip | string | optional | Text for button tooltip. |
| enabled | boolean | optional | default: `true` - Represents the button’s state. When `false`, the button is unclickable. Toggled by the button’s API. |
| active | boolean | optional | default: `false` - Represents the button’s state. When `true`, the button is highlighted. Toggled by the button’s API. |
| onSetup | `(api) => (api) => void` | optional | default: `() => () => {}` - Function invoked when the button is rendered. For details, see: [Using `onSetup`](#using-onsetup). |
| onAction | `(api) => void` | required | Function invoked when the button is clicked. |
| NOTE: This feature is only available for TinyMCE 7.0 and later. | NOTE: This feature is only available for TinyMCE 7.0 and later. | NOTE: This feature is only available for TinyMCE 7.0 and later. | NOTE: This feature is only available for TinyMCE 7.0 and later. |
| shortcut | string | optional | Shortcut to display in the tooltip. To register a shortcut, see: [Add custom shortcuts to TinyMCE](../shortcuts/). |
| NOTE: This feature is only available for TinyMCE 7.4 and later. | NOTE: This feature is only available for TinyMCE 7.4 and later. | NOTE: This feature is only available for TinyMCE 7.4 and later. | NOTE: This feature is only available for TinyMCE 7.4 and later. |
| context | string | optional | default: `mode:design` - The context property dynamically enables or disables the button based on the editor’s current state. For details, see: [Context](../context/). |

## 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 if the button is `on`. |
| setActive | `(state: boolean) => void` | Sets the button’s toggle state. |
| NOTE: This feature is only available for TinyMCE 6.4 and later. | NOTE: This feature is only available for TinyMCE 6.4 and later. | NOTE: This feature is only available for TinyMCE 6.4 and later. |
| setText | `(text: string) => void` | Sets the text label to display. |
| setIcon | `(icon: string) => void` | Sets the icon of the button. |

## Toggle button example and explanation

**Example**

```js
tinymce.init({
  selector: 'textarea#custom-toolbar-toggle-button',
  toolbar: 'customStrikethrough customToggleStrikethrough',
  setup: (editor) => {
    editor.ui.registry.addToggleButton('customStrikethrough', {
      text: 'Strikethrough',
      onAction: (api) => {
        editor.execCommand('mceToggleFormat', false, 'strikethrough');
        api.setActive(!api.isActive());
      }
    });

    editor.ui.registry.addToggleButton('customToggleStrikethrough', {
      icon: 'strike-through',
      onAction: (_) => editor.execCommand('mceToggleFormat', false, 'strikethrough'),
      onSetup: (api) => {
        api.setActive(editor.formatter.match('strikethrough'));
        const changed = editor.formatter.formatChanged('strikethrough', (state) => api.setActive(state));
        return () => changed.unbind();
      }
    });
  },
  content_style: 'body { font-family:Helvetica,Arial,sans-serif; font-size:16px }'
});
```
The example above adds two custom **strikethrough** buttons with the same `onAction` configuration. The configuration uses `editor.execCommand(command, ui, args)` to execute `mceToggleFormat`. This editor method toggles the specified format on and off, but only works for [formats](../content-formatting/#formats) that are already registered with the editor. In this example, `strikethrough` is the registered format.

The first button applies and removes strikethrough formatting, and its state toggles on click using `api.setActive(!api.isActive())`. However, the expected behavior is that the button’s state will reflect whether the selected content has strikethrough formatting. For example, if the cursor is moved into editor content that has strikethrough formatting the button will become **active** and if it is moved into content that does not have strikethrough formatting the button will become **inactive**. The first button in the example does not do this, since its state only toggles when the button is clicked.

To achieve this, the second button uses `onSetup` to register a callback for strikethrough content using `editor.formatter.formatChanged(formatName, callback)`. This method executes the specified callback function when the selected content has the specified formatting.

> **Note:** The format name given to `mceToggleFormat` via `editor.execCommand(command, ui, args)` and to `editor.formatter.formatChanged(formatName, callback)` is the same.
The callback given to `editor.formatter.formatChanged` is a function that takes a `state` boolean representing whether the currently selected content contains the applied format. This `state` boolean is used to set the button’s active state to match if the selected content has the specified formatting by using `api.setActive(state)` from the button’s API. This ensures the `customToggleStrikethrough` button is only **active** when the selected content contains the strikethrough formatting.

For formats that require variables, the `editor.formatter.formatChanged` function takes two extra arguments: `similar` and `vars`.

When the `similar` argument is `true`, similar formats will all be treated as the same by `formatChanged`. Similar formats are those with the same `formatName` but different variables. This argument will default to `false`.

The `vars` argument controls which variables are used to match the content when determining whether to run the callback. This argument is only used when `similar` is `false`.

## 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:

```js
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)`.

> **Note:**
> - 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 () => {};`.
