---
title: "Custom Toggle menu items"
description: "How to create custom Toggle menu items."
canonical_url: "https://www.tiny.cloud/docs/tinymce/latest/custom-toggle-menu-items/"
md_url: "https://www.tiny.cloud/docs/tinymce/latest/custom-toggle-menu-items/index.md"
version: "latest"
last_updated: "2026-09-24T22:40:35Z"
tokens: 1053
---
# Custom Toggle menu items

A toggle menu item triggers its `onAction` when clicked. It also has a concept of state. This means it can be toggled `on` and `off`. A toggle menu item gives the user visual feedback for its state through a checkmark that appears to the right of the menu item’s text when it is `on`.

## Options

| Name | Value | Requirement | Description |
| --- | --- | --- | --- |
| 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](../editor-icon-identifiers/), in a [custom icon pack](../creating-an-icon-pack/), or added using the [`addIcon` API](../apis/tinymce.editor.ui.registry/#addIcon). |
| value | string | optional | A value to associate with the menu item. |
| active | boolean | optional | default: `false` - Initial state value for the toggle menu item. |
| 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. |
| onSetup | `(api) => (api) => void` | optional | default: `() => () => {}` - Function invoked when the menu item is rendered, each time its menu is opened. For details, see: [Using `onSetup`](#using-onsetup). |
| onAction | `(api) => void` | required | Function invoked when the menu item is clicked. |
| context | string | optional | default: `mode:design` - The context property dynamically enables or disables the menu item based on the editor’s current state. For details, see: [Context](../context/). |

## API

| Name | Value | Description |
| --- | --- | --- |
| isActive | `() => boolean` | Checks if the menu item is active. |
| setActive | `(state: boolean) => void` | Sets the menu item’s active state. |
| isEnabled | `() => boolean` | Checks if the menu item is enabled. |
| setEnabled | `(state: boolean) => void` | Sets the menu item’s enabled state. |

## Example: creating a toggle menu item

```js
// Menu items are recreated when the menu is closed and opened, so we need
// a variable to store the toggle menu item state.
let toggleState = false;

tinymce.init({
  selector: 'textarea',
  menu: {
    custom: { title: 'Custom Menu', items: 'undo redo toggleitem' }
  },
  menubar: 'file edit custom',
  setup: (editor) => {
    editor.ui.registry.addToggleMenuItem('toggleitem', {
      text: 'My toggle menu item',
      icon: 'home',
      onAction: () => {
        toggleState = !toggleState;
        alert('Toggle menu item clicked');
      },
      onSetup: (api) => {
        api.setActive(toggleState);
        return () => {};
      }
    });
  }
});
```

## Using `onSetup`

`onSetup` accepts a function that receives the component’s API. This function should return a callback that returns nothing after being passed the component’s API. This occurs because `onSetup` runs whenever the component is rendered, and the callback returned by `onSetup` is executed when the component is destroyed. The function returned from `onSetup` 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) => {
  // Runs when the component is created
  // Configure the component or bind event listeners

  return (api) => {
    // Runs when the component is destroyed
    // Unbind event listeners or clean up resources
  };
};
```
To bind a callback function to an editor event use [`editor.on(eventName, callback)`](../apis/tinymce.editor/#on). To unbind an event listener use [`editor.off(eventName, callback)`](../apis/tinymce.editor/#off). 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 passed to `editor.off()` should be the same function passed to `editor.on()`. For example, if an `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 register any event listeners or only listens to the `init` event, `onSetup` can return an empty function e.g. `return () => {};`.
