---
title: "TinyMCE AI Plugin"
description: "AI-powered features for TinyMCE AI including AI chat, AI review, and quick actions"
canonical_url: "https://www.tiny.cloud/docs/tinymce/latest/tinymceai/"
md_url: "https://www.tiny.cloud/docs/tinymce/latest/tinymceai/index.md"
version: "latest"
last_updated: "2026-08-31T06:13:46Z"
tokens: 11906
---
# TinyMCE AI Plugin

> **Note:** This plugin is only available for [paid TinyMCE subscriptions](/pricing/).

> **Note:** This feature is not supported when TinyMCE is run in *inline* mode. It is only supported in *classic* mode. For more information on the differences between the editing modes, see [Inline editing mode](../use-tinymce-inline/).
The TinyMCE AI plugin integrates AI-assisted authoring with rich-text editing. Users can interact through Actions, Reviews, or Conversations that can use relevant context from multiple sources.

> **Note:** The TinyMCE AI plugin requires TinyMCE 8.4 or later.

## Interactive example

**Example**

```js
// Step 1: Set up session - this should be part of the application's user management process.
// Open-source plugins below are only for editing the demo HTML (lists, links, tables). TinyMCE AI options are the focus.
tinymce.init({
  selector: 'textarea#tinymceai',
  height: '800px',
  plugins: ['tinymceai', 'advlist', 'lists', 'link', 'autolink', 'table', 'wordcount'],
  toolbar: 'undo redo | tinymceai-chat ai-quickactions-translate tinymceai-review | styles | bold italic underline strikethrough | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link',
  sidebar_show: 'tinymceai-chat',
  tinymceai_chat_welcome_message: '<p>Welcome to TinyMCE AI. Pick an action below or type your own prompt.</p>',
  tinymceai_chat_welcome_actions: [
    { text: 'Here are some actions to get started:' },
    { title: 'Summarize the document', command: 'TinyMCEAIQuickActionsSummarize' },
    { title: 'Continue writing', command: 'TinyMCEAIQuickActionContinueWriting' },
    { title: 'Translate to Spanish', command: 'TinyMCEAIQuickActionTranslate', value: 'spanish' },
    { title: 'Review my document', command: 'ToggleSidebar', value: 'tinymceai-review' }
  ],
  tinymceai_token_provider: async () => {
    return fetch('/api/tinymceai-token', { credentials: 'include' })
      .then(resp => resp.text())
      .then(token => ({ token }));
  },
  tinymceai_chat_fetch_sources: () => Promise.resolve([{
    label: 'TinyMCE resources',
    sources: [
      { id: 'docs', label: 'TinyMCE Documentation', type: 'web-resource' },
      { id: 'blog', label: 'Tiny Blog', type: 'web-resource' },
      { id: 'survey-2023', label: 'State of rich text editing 2023', type: 'web-resource' },
    ]
  }]),
  tinymceai_chat_fetch_source: (id) => {
    const urls = {
      'docs': 'https://www.tiny.cloud/docs/tinymce/latest/',
      'blog': 'https://www.tiny.cloud/blog/',
      'survey-2023': 'https://www.tiny.cloud/developer-survey-results-2023/',
    };
    return Promise.resolve({ type: 'web-resource', url: urls[id] });
  },
  tinymceai_quickactions_custom: [
    {
      type: 'chat',
      title: 'Challenge',
      prompt: 'Challenge statements, verify facts and identify assumptions'
    }
  ],
  tinymceai_languages: [
    { title: 'English', language: 'english' },
    { title: 'Chinese (Simplified)', language: 'chinese' },
    { title: 'Spanish', language: 'spanish' },
    { title: 'German', language: 'german' },
    { title: 'Japanese', language: 'japanese' },
    { title: 'Portuguese', language: 'portuguese' },
    { title: 'Swedish', language: 'swedish' },
    { title: 'Korean', language: 'korean' },
    { title: 'Hindi (Devanagari)', language: 'hindi devanagari' },
    { title: 'Italian', language: 'italian' },
    { title: 'Klingon', language: 'klingon' },
    { title: 'Dothraki', language: 'dothraki' },
  ]
});
```

## Availability

The TinyMCE AI plugin can be deployed with either a Tiny Cloud or a self-hosted TinyMCE editor:

- **Tiny Cloud**: load the plugin from the Tiny Cloud CDN.
- **Self-hosted**: from TinyMCE 8.7.0, install the plugin from the `tinymce-premium` NPM package, or as a standalone addon `.zip` download from the [Tiny Account](/my-account).

The `tinymceai` plugin is distributed only as a standalone addon. It is not included in any TinyMCE ZIP bundle.

For self-hosted installation steps, see [Install premium plugins from NPM](../npm-projects/#install-premium-plugins) or [Installing TinyMCE using a .zip file](../installation-zip/).

> **Note:** The plugin requires an AI service to operate. Use the hosted Tiny Cloud AI service, or deploy the [self-hosted AI service](../tinymceai-on-premises/) to keep content within the host network. In both cases, a [JWT token endpoint](../tinymceai-jwt-authentication-intro/) handles authentication.

## Basic setup

To set up the TinyMCE AI plugin in TinyMCE:

- add `tinymceai` to the `plugins` option in the editor configuration;
- configure the `tinymceai_token_provider` option to provide authentication tokens (must return `{ token: string }`). During a Tiny Cloud trial, the [demo identity service](../tinymceai-jwt-authentication-intro/#trial-demo-identity-service) can supply JWTs so a custom token endpoint is not required;
- when the `toolbar` option is omitted or left at the default, the Silver theme toolbar already includes the AI toolbar buttons once the plugin is enabled: `tinymceai-chat`

![Chat icon](../_images/icons-premium/ai-assistant.svg)
, `tinymceai-quickactions`
![Quick Actions icon](../_images/icons/ai-prompt.svg)
, and `tinymceai-review`
![Review icon](../_images/icons-premium/ai-review.svg)
. When a custom `toolbar` string is set, add those button ids to the string explicitly.

> **Note:** When using the cloud-hosted service behind a firewall or forward proxy, ensure `*.tiny.cloud` is allowlisted and that required HTTP headers are not stripped. See [Firewall and proxy allowlisting](../tinymce-and-csp/#firewall-and-proxy-allowlisting) for details.

### Minimal setup

The following configuration enables the plugin and token provider and relies on the default toolbar, which includes the AI buttons. If the `toolbar` option is set to a custom string, add `tinymceai-chat`, `tinymceai-quickactions`, and `tinymceai-review` to that string.

```js
tinymce.init({
  selector: 'textarea',  // change this value according to the HTML
  plugins: 'tinymceai',
  tinymceai_token_provider: () => {
    return fetch('/api/token').then(r => r.json());
  }
});
```

### Complete setup example

The following example sets a custom `toolbar` string. To use the default toolbar instead (which already includes the AI buttons), omit the `toolbar` option.

```js
tinymce.init({
  selector: 'textarea',  // change this value according to the HTML
  plugins: 'tinymceai',
  toolbar: 'tinymceai-chat tinymceai-quickactions tinymceai-review',
  content_id: 'document-123',
  // Required for authentication
  tinymceai_token_provider: () => {
    return fetch('/api/token').then(r => r.json());
  },
  tinymceai_default_model: 'agent-1',
  tinymceai_allow_model_selection: true,
  tinymceai_chat_fetch_sources: async () => [
    {
      label: 'My Documents',
      sources: [
        { id: 'doc-1', label: 'Document 1', type: 'file' },
        { id: 'url-1', label: 'Web Page', type: 'web-resource' }
      ]
    }
  ],
  tinymceai_chat_fetch_source: async (id) => {
    const res = await fetch(`/api/documents/${id}`);
    const blob = await res.blob();
    const filename = `${id}.pdf`;
    return { type: 'file', file: new File([blob], filename, { type: blob.type }) };
  },
  tinymceai_quickactions_custom: [
    { title: 'Explain like I am five', prompt: 'Explain the following text in simple terms.', type: 'chat' }
  ]
});
```

## Options

The following configuration options affect the behavior of the TinyMCE AI plugin.

Configuration options are grouped by the feature they configure. Options in the General section apply to the plugin as a whole or to multiple features.

### General options

These options apply to the plugin overall or to multiple AI features (Chat, Quick Actions, Review).

> **Tip:** For context toolbar use cases (a toolbar that appears when text is selected), use the [Quick Toolbars](../quickbars/) plugin and configure `quickbars_selection_toolbar` with the desired control identifiers.

#### `content_id`

A unique identifier for the document or content being edited. When set, the chat history shown for the user is scoped to this ID, allowing conversations to be preserved and associated with the specific document across sessions. When not set, all conversations for the user are shown regardless of document.

**Type:** `String`

**Default value:** `undefined`

Example
```js
tinymce.init({
  selector: 'textarea',
  plugins: 'tinymceai',
  toolbar: 'tinymceai-chat tinymceai-quickactions tinymceai-review',
  content_id: 'document-123',
  // Required for authentication
  tinymceai_token_provider: () => {
    return fetch('/api/token').then(r => r.json());
  }
});
```

#### `tinymceai_token_provider`

A function that returns a Promise resolving to an object with a `token` property containing the signed JWT token for authenticating with the TinyMCE AI service.

**Type:** `Function` (`() => Promise<{ token: string }>`)

**Default value:** `undefined`

The JWT payload must include these required claims:

- `iat`: Issued at time (provided by JWT libraries)
- `exp`: Expiration time (tokens cannot exceed 24 hours; 5-15 minutes recommended)
- `aud`: The TinyMCE API key
- `auth`: Authentication object
- `sub`: Unique user ID

For more information about JWT setup, required claims, and the authentication object, see [JWT Authentication](../tinymceai-jwt-authentication-intro/).

> **Note:** During a Tiny Cloud trial, a [demo identity service](../tinymceai-jwt-authentication-intro/#trial-demo-identity-service) is available so `tinymceai_token_provider` can obtain JWTs without implementing a custom token endpoint. See [JWT Authentication](../tinymceai-jwt-authentication-intro/) for setup and examples.
The function must return the token value within an object with a `token` property. Ensure the response from the token endpoint is handled correctly, based on the response format:

- **JSON response**: Endpoint returns `{ "token": "eyJ..." }`. Use `fetch(url).then(r => r.json())`.
- **Plain text response**: Endpoint returns the raw JWT string. Use `fetch(url).then(r => r.text()).then(token => ({ token }))`.

Example: JSON response from custom endpoint
```js
tinymce.init({
  selector: 'textarea',
  plugins: 'tinymceai',
  toolbar: 'tinymceai-chat tinymceai-quickactions tinymceai-review',
  tinymceai_token_provider: () => {
    return fetch('/api/tinymceai-token').then(r => r.json());
  }
});
```
Example: Plain text response from custom endpoint
```js
tinymce.init({
  selector: 'textarea',
  plugins: 'tinymceai',
  toolbar: 'tinymceai-chat tinymceai-quickactions tinymceai-review',
  tinymceai_token_provider: () => {
    return fetch('/api/token').then(r => r.text()).then(token => ({ token }));
  }
});
```

#### `tinymceai_sidebar_type`

Controls how the AI sidebar is displayed. With `static`, the sidebar renders inside the editor. With `floating`, it renders in a separate container outside the editor and can be dragged on the page.

**Type:** `String`

**Possible Values:** `'static'`, `'floating'`

**Default value:** `'static'`

Example
```js
tinymce.init({
  selector: 'textarea',
  plugins: 'tinymceai',
  toolbar: 'tinymceai-chat tinymceai-quickactions tinymceai-review',
  tinymceai_sidebar_type: 'floating',
  // Required for authentication
  tinymceai_token_provider: () => {
    return fetch('/api/token').then(r => r.json());
  }
});
```

> **Note:** Changing this property dynamically (after the editor has been initialized) is not supported and can result in unpredictable behavior.

#### `tinymceai_default_model`

The default AI model to use when no model is explicitly selected by the user. If undefined, the AI service will select the best model for speed, quality, and cost.

**Type:** `String`

**Default value:** `undefined`

Example
```js
tinymce.init({
  selector: 'textarea',
  plugins: 'tinymceai',
  toolbar: 'tinymceai-chat tinymceai-quickactions tinymceai-review',
  tinymceai_default_model: 'gemini-2-5-flash',
  // Required for authentication
  tinymceai_token_provider: () => {
    return fetch('/api/token').then(r => r.json());
  }
});
```

#### `tinymceai_allow_model_selection`

Whether users can select a different AI model from the chat interface.

**Type:** `Boolean`

**Possible Values:** `true`, `false`

**Default value:** `true`

Example
```js
tinymce.init({
  selector: 'textarea',
  plugins: 'tinymceai',
  toolbar: 'tinymceai-chat tinymceai-quickactions tinymceai-review',
  tinymceai_allow_model_selection: false,
  // Required for authentication
  tinymceai_token_provider: () => {
    return fetch('/api/token').then(r => r.json());
  }
});
```

### Options for Chat

These options configure the AI Chat sidebar, where users have interactive conversations with the AI and can add external sources for context.

#### `tinymceai_chat_fetch_sources`

Populates the sources menu with submenus of files and web resources. Users can select these sources as additional context for chat conversations. The option can also nominate default sources, which the TinyMCE AI plugin adds to the context of every new conversation.

Takes a function that returns a Promise resolving to either of the following:

- An array of source groups.
- An object with a `menu` property, holding the array of source groups, and a `defaults` property, holding an array of source identifiers.

Each source group has `label`, optional `icon`, and `sources` array. Each source has `id`, `label`, and `type` (`'web-resource'` or `'file'`). A source’s `id` is used to fetch its content through [`tinymceai_chat_fetch_source`](#tinymceai_chat_fetch_source).

Both shapes are supported. Returning an array populates the sources menu without nominating any default sources.

Each identifier listed in `defaults` must match the `id` of a source listed in `sources`. The plugin adds each matching source to the context of every new conversation, and shows it as selected in the sources menu. Identifiers without a matching source are not added to the context, and the plugin logs an error in the browser console. Users can remove a default source from a conversation and add it again from the sources menu.

If `menu` is missing or empty, the plugin logs an error in the browser console and populates no sources.

**Type:** `Function` (`() => Promise<Array | Object>`)

**Possible Values:** For source `type` property: `'web-resource'`, `'file'`

**Default value:** `() => Promise.resolve([])`

Example: populating the sources menu
```js
tinymce.init({
  selector: 'textarea',
  plugins: 'tinymceai',
  toolbar: 'tinymceai-chat tinymceai-quickactions tinymceai-review',
  tinymceai_chat_fetch_sources: async () => [
    {
      label: 'My Documents',
      icon: 'folder',
      sources: [
        { id: 'doc-1', label: 'Document 1', type: 'file' },
        { id: 'url-1', label: 'Web Page', type: 'web-resource' }
      ]
    }
  ],
  tinymceai_chat_fetch_source: async (id) => {
    const res = await fetch(`/api/documents/${id}`);
    const blob = await res.blob();
    const filename = `${id}.pdf`;
    return { type: 'file', file: new File([blob], filename, { type: blob.type }) };
  },
  // Required for authentication
  tinymceai_token_provider: () => {
    return fetch('/api/token').then(r => r.json());
  }
});
```
Example: nominating default sources
```js
tinymce.init({
  selector: 'textarea',
  plugins: 'tinymceai',
  toolbar: 'tinymceai-chat tinymceai-quickactions tinymceai-review',
  tinymceai_chat_fetch_sources: async () => ({
    defaults: [ 'doc-1' ],
    menu: [
      {
        label: 'My Documents',
        icon: 'folder',
        sources: [
          { id: 'doc-1', label: 'Style guide', type: 'file' },
          { id: 'url-1', label: 'Web Page', type: 'web-resource' }
        ]
      }
    ]
  }),
  tinymceai_chat_fetch_source: async (id) => {
    const res = await fetch(`/api/documents/${id}`);
    const blob = await res.blob();
    const filename = `${id}.pdf`;
    return { type: 'file', file: new File([blob], filename, { type: blob.type }) };
  },
  // Required for authentication
  tinymceai_token_provider: () => {
    return fetch('/api/token').then(r => r.json());
  }
});
```

#### `tinymceai_chat_fetch_source`

A function that fetches the content for an additional source by ID. Receives the source `id` and returns a Promise resolving to the source content (either `{ type: 'file', file: File }` or `{ type: 'web-resource', url: string }`). The content is passed to the AI agent as additional context for the chat conversation.

**Type:** `Function` (`(id: string) => Promise<Object>`)

**Possible Values:** For return object `type` property: `'file'`, `'web-resource'`

**Default value:** `(id) => Promise.resolve(`Should fetch additional source with given ${id}`)`

Example
```js
tinymce.init({
  selector: 'textarea',
  plugins: 'tinymceai',
  toolbar: 'tinymceai-chat tinymceai-quickactions tinymceai-review',
  tinymceai_chat_fetch_sources: async () => [
    { label: 'Docs', sources: [{ id: 'doc-1', label: 'Document 1', type: 'file' }] }
  ],
  tinymceai_chat_fetch_source: async (id) => {
    const res = await fetch(`/api/documents/${id}`);
    const blob = await res.blob();
    const filename = `${id}.pdf`;
    return { type: 'file', file: new File([blob], filename, { type: blob.type }) };
  },
  // Required for authentication
  tinymceai_token_provider: () => {
    return fetch('/api/token').then(r => r.json());
  }
});
```

#### `tinymceai_chat_welcome_message`

Customizes the welcome message displayed in the Chat sidebar when starting a new conversation.

**Type:** `String`

**Default value:** A default message introducing the AI assistant and its capabilities.

Example
```js
tinymce.init({
  selector: 'textarea',
  plugins: 'tinymceai',
  toolbar: 'tinymceai-chat tinymceai-quickactions tinymceai-review',
  tinymceai_chat_welcome_message: '<p>Welcome! How can I help you today?</p>',
  // Required for authentication
  tinymceai_token_provider: () => {
    return fetch('/api/token').then(r => r.json());
  }
});
```

#### `tinymceai_chat_welcome_actions`

Adds a set of suggested welcome actions to the Chat sidebar empty state, shown below the [`tinymceai_chat_welcome_message`](#tinymceai_chat_welcome_message) when a conversation is empty. Welcome actions give users a set of starting points instead of a blank prompt. The actions are shown only before the first request is sent. They are hidden after the first request and shown again when a new conversation is started.

**Type:** `Array`

**Default value:** `[]` (no welcome actions)

Each item in the array is one of the following:

- A `String`, or an object with a `text` property (`{ text: 'string' }`), shown as descriptive text.
- An action object, shown as a clickable button, with the following properties:

  - `title` (`String`): The label shown on the button.
  - `command` (`String`): The editor command run when the button is selected. The command runs without moving focus into the editor, so the editor scroll position is preserved. This can be a Quick Action or Chat command, the core `ToggleSidebar` command, or any other registered editor command, such as `Bold`. For the AI command names, see [TinyMCE AI](../editor-command-identifiers/#tinymceai).
  - `value` (optional): The argument passed to the command. The accepted value matches the command, for example a language label for `TinyMCEAIQuickActionTranslate`, a `{ prompt, displayedPrompt }` object for `TinyMCEAIChatPrompt`, or a sidebar name such as `'tinymceai-review'` for `ToggleSidebar`.
  - `icon` (optional `String`): The name of the icon shown on the button, using any editor icon identifier. When omitted, an icon is selected automatically based on the command.

Text items and action buttons can be interleaved to group related actions under short headings.

Example
```js
tinymce.init({
  selector: 'textarea',
  plugins: 'tinymceai',
  toolbar: 'tinymceai-chat tinymceai-quickactions tinymceai-review',
  tinymceai_chat_welcome_actions: [
    { text: 'Here are some actions to get started:' },
    { title: 'Summarize the document', command: 'TinyMCEAIQuickActionsSummarize' },
    { title: 'Continue writing', command: 'TinyMCEAIQuickActionContinueWriting' },
    { title: 'Translate to Spanish', command: 'TinyMCEAIQuickActionTranslate', value: 'spanish' },
    {
      title: 'Draft a reply',
      command: 'TinyMCEAIChatPrompt',
      value: { prompt: 'Draft a reply to this message in a professional tone.', displayedPrompt: 'Draft a reply' }
    },
    { title: 'Review my document', command: 'ToggleSidebar', value: 'tinymceai-review' },
    { text: 'Other editor commands are also supported:' },
    { title: 'Bold', command: 'Bold', icon: 'bold' }
  ],
  // Required for authentication
  tinymceai_token_provider: () => {
    return fetch('/api/token').then(r => r.json());
  }
});
```

#### `tinymceai_tool_data_callback`

Customizes the status message shown in the Chat sidebar while the AI model calls a Model Context Protocol (MCP) tool. The function runs when the MCP server sends an `mcp-tool-result` or `mcp-tool-notification` event during a streaming response. The function returns a string to display as the status message, or returns `undefined` to fall back to the default status message.

**Type:** `Function` (`(event: MCPToolEvent) => string | undefined`)

**Default value:** `undefined`

The function receives a single `event` argument, which is one of the following objects:

- An `mcp-tool-result` event, sent when a tool returns a result:

  - `type`: `'mcp-tool-result'`
  - `toolName` (`String`): The name of the tool that ran.
  - `result` (`String`): The result the tool returns.
  - `success` (`Boolean`): Whether the tool call succeeded.
- An `mcp-tool-notification` event, sent when a tool reports progress or a log message:

  - `type`: `'mcp-tool-notification'`
  - `toolName` (`String`): The name of the tool that sent the notification.
  - `level` (`String`): The severity of the notification. One of `'error'`, `'info'`, `'debug'`, `'notice'`, `'warning'`, `'critical'`, `'alert'`, or `'emergency'`.
  - `data`: The data included with the notification.

A common use is to map each tool name to a human-readable message. For example, the callback can display `Searching the knowledge base...` while a `search-knowledge-base` tool runs.

Example
```js
tinymce.init({
  selector: 'textarea',
  plugins: 'tinymceai',
  toolbar: 'tinymceai-chat tinymceai-quickactions tinymceai-review',
  tinymceai_tool_data_callback: (event) => {
    // Map tool names to human-readable status messages
    const statusMessages = {
      'search-knowledge-base': 'Searching the knowledge base...'
    };
    if (event.type === 'mcp-tool-result') {
      return statusMessages[event.toolName] || `Running ${event.toolName}...`;
    }
    // Use the default status message for other events
    return undefined;
  },
  // Required for authentication
  tinymceai_token_provider: () => {
    return fetch('/api/token').then(r => r.json());
  }
});
```

### Options for Quick Actions

These options configure the Quick Actions menu, which provides one-click AI transformations such as writing and grammar improvements, translation, and tone changes.

#### `tinymceai_quickactions_menu`

Array of control IDs that define the order of items in the Quick Actions menu. The default value includes all default items, including `ai-quickactions-custom` which adds a submenu of custom actions defined by `tinymceai_quickactions_custom`.

**Type:** `Array` of `String`

**Default value:**

```js
[
  'ai-quickactions-chat-prompts',
  'ai-quickactions-improve-writing',
  'ai-quickactions-continue-writing',
  'ai-quickactions-check-grammar',
  'ai-quickactions-change-length',
  'ai-quickactions-change-tone',
  'ai-quickactions-translate',
  'ai-quickactions-custom'
]
```
Example
```js
tinymce.init({
  selector: 'textarea',
  plugins: 'tinymceai',
  toolbar: 'tinymceai-chat tinymceai-quickactions tinymceai-review',
  tinymceai_quickactions_menu: [
    'ai-quickactions-improve-writing',
    'ai-quickactions-check-grammar',
    'ai-quickactions-custom'
  ],
  // Required for authentication
  tinymceai_token_provider: () => {
    return fetch('/api/token').then(r => r.json());
  }
});
```

#### `tinymceai_quickactions_chat_prompts`

Array of control IDs for the Chat Commands submenu within the AI Quick Actions menu.

**Type:** `Array` of `String`

**Default value:** `['ai-chat-explain', 'ai-chat-summarize', 'ai-chat-highlight-key-points']`

Example
```js
tinymce.init({
  selector: 'textarea',
  plugins: 'tinymceai',
  toolbar: 'tinymceai-chat tinymceai-quickactions tinymceai-review',
  tinymceai_quickactions_chat_prompts: [
    'ai-chat-explain',
    'ai-chat-summarize',
    'ai-chat-highlight-key-points'
  ],
  // Required for authentication
  tinymceai_token_provider: () => {
    return fetch('/api/token').then(r => r.json());
  }
});
```

#### `tinymceai_quickactions_change_tone_menu`

Array of control IDs for the Change Tone submenu within the AI Quick Actions menu.

**Type:** `Array` of `String`

**Default value:**

```js
[
  'ai-quickactions-tone-casual',
  'ai-quickactions-tone-direct',
  'ai-quickactions-tone-friendly',
  'ai-quickactions-tone-confident',
  'ai-quickactions-tone-professional'
]
```
Example
```js
tinymce.init({
  selector: 'textarea',
  plugins: 'tinymceai',
  toolbar: 'tinymceai-chat tinymceai-quickactions tinymceai-review',
  tinymceai_quickactions_change_tone_menu: [
    'ai-quickactions-tone-casual',
    'ai-quickactions-tone-professional'
  ],
  // Required for authentication
  tinymceai_token_provider: () => {
    return fetch('/api/token').then(r => r.json());
  }
});
```

#### `tinymceai_languages`

Array of language options for the Translate submenu within the AI Quick Actions menu. Each item has `title` (displayed in the menu) and `language` (language name or label sent to the API, for example `'english'`, `'chinese'`).

The `language` string is passed to the API as the target language description. Values are not limited to the built-in examples: any clear label the model can interpret can be used (including informal or regional phrasing).

**Type:** `Array` of `Object`

**Default value:**

```js
[
  { title: 'English', language: 'english' },
  { title: 'Chinese (Simplified)', language: 'chinese' },
  { title: 'Spanish', language: 'spanish' },
  { title: 'German', language: 'german' },
  { title: 'Japanese', language: 'japanese' },
  { title: 'Portuguese', language: 'portuguese' },
  { title: 'Korean', language: 'korean' },
  { title: 'Italian', language: 'italian' },
  { title: 'Russian', language: 'russian' }
]
```
Example
```js
tinymce.init({
  selector: 'textarea',
  plugins: 'tinymceai',
  toolbar: 'tinymceai-chat tinymceai-quickactions tinymceai-review',
  tinymceai_languages: [
    { title: 'English', language: 'english' },
    { title: 'French', language: 'french' },
    { title: 'German', language: 'german' }
  ],
  // Required for authentication
  tinymceai_token_provider: () => {
    return fetch('/api/token').then(r => r.json());
  }
});
```

#### `tinymceai_quickactions_custom`

Array of custom actions rendered in the Custom submenu within the AI Quick Actions menu. Each item can be type `action` (quick action with immediate preview) or type `chat` (opens in chat).

- `title`: Text shown in the menu and chat history
- `prompt`: The prompt sent to the AI
- `type`: `'action'` or `'chat'`
- `model`: Required for `action` type only
- `id` (optional): Stable identifier for the custom action. When set, the same string can be listed in [`tinymceai_quickactions_menu`](#tinymceai_quickactions_menu) so the action appears as its own top-level menu item instead of only inside the Custom submenu. The identifier can also be used in the [`menu`](../menus-configuration-options/#menu) option or any other menu configuration that accepts menu item identifiers.

**Type:** `Array` of `Object`

**Possible Values:** For `type` property: `'action'`, `'chat'`

**Default value:** `[]`

Example
```js
tinymce.init({
  selector: 'textarea',
  plugins: 'tinymceai',
  toolbar: 'tinymceai-chat tinymceai-quickactions tinymceai-review',
  tinymceai_quickactions_custom: [
    {
      title: 'Add a quote from a famous person',
      prompt: 'Add a quote from a known person, which would make sense in the context of the selected text.',
      type: 'action',
      model: 'gemini-2-5-flash'
    },
    {
      title: 'Summarize in 5 bullet points',
      prompt: 'Summarize the selected text in 5 bullet points.',
      type: 'chat'
    }
  ],
  // Required for authentication
  tinymceai_token_provider: () => {
    return fetch('/api/token').then(r => r.json());
  }
});
```
Example: custom actions as top-level Quick Actions menu items using `id`
```js
tinymce.init({
  selector: 'textarea',
  plugins: 'tinymceai',
  toolbar: 'tinymceai-chat tinymceai-quickactions tinymceai-review',
  tinymceai_quickactions_menu: [
    'ai-quickactions-chat-prompts',
    'ai-quote',
    'ai-summarize'
  ],
  tinymceai_quickactions_custom: [
    {
      id: 'ai-quote',
      title: 'Add a quote from a famous person',
      prompt: 'Add a quote from a known person, which would make sense in the context of the selected text.',
      type: 'action',
      model: 'gemini-2-5-flash'
    },
    {
      id: 'ai-summarize',
      title: 'Summarize in 5 bullet points',
      prompt: 'Summarize the selected text in 5 bullet points.',
      type: 'chat'
    }
  ],
  tinymceai_token_provider: () => {
    return fetch('/api/token').then(r => r.json());
  }
});
```

### Options for Review

These options configure the AI Review sidebar, which provides content quality analysis and improvement suggestions.

#### `tinymceai_reviews`

Array that defines which reviews appear in the Review sidebar and their order. Only the listed reviews are available to users. Each item is either a built-in review command ID (a string) or an [integrator-defined review](#integrator-defined-reviews) (an object).

**Type:** `Array` of `String` or `Object`

**Valid values:**

- `'ai-reviews-proofread'`: Check grammar, spelling, and punctuation
- `'ai-reviews-improve-clarity'`: Improve logical structure and precision
- `'ai-reviews-improve-readability'`: Adjust sentence structure and word choice
- `'ai-reviews-change-length'`: Shorten or lengthen text
- `'ai-reviews-change-tone'`: Modify tone and style
- `'ai-reviews-custom'`: [Custom review](../tinymceai-review/#custom-review-choose-review) — accepts a prompt and model, then runs the same streaming preview and apply flow as other reviews

To hide Custom review from the Review sidebar, omit `'ai-reviews-custom'` from the array.

**Default value:**

```js
[
  'ai-reviews-proofread',
  'ai-reviews-improve-clarity',
  'ai-reviews-improve-readability',
  'ai-reviews-change-length',
  'ai-reviews-change-tone',
  'ai-reviews-custom'
]
```
Example
```js
tinymce.init({
  selector: 'textarea',
  plugins: 'tinymceai',
  toolbar: 'tinymceai-chat tinymceai-quickactions tinymceai-review',
  tinymceai_reviews: [
    'ai-reviews-proofread',
    'ai-reviews-improve-clarity',
    'ai-reviews-change-tone'
  ],
  // Required for authentication
  tinymceai_token_provider: () => {
    return fetch('/api/token').then(r => r.json());
  }
});
```

#### `tinymceai_reviews_change_tone_menu`

Array of tone IDs that define which tone options appear in the Change Tone review and their order. Only the listed tones appear in the menu.

This option applies only when `'ai-reviews-change-tone'` is included in the [`tinymceai_reviews`](#tinymceai_reviews) option.

**Type:** `Array` of `String`

**Valid values:**

- `'ai-reviews-tone-casual'`: Casual tone
- `'ai-reviews-tone-direct'`: Direct tone
- `'ai-reviews-tone-friendly'`: Friendly tone
- `'ai-reviews-tone-confident'`: Confident tone
- `'ai-reviews-tone-professional'`: Professional tone

Duplicate IDs are removed, and the menu displays tones in the configured order. If the option includes an invalid tone ID, the configuration is rejected and the default tones are used. An empty array (`[]`) is accepted, but TinyMCE logs a console warning. To remove the Change Tone review entirely, omit `'ai-reviews-change-tone'` from the [`tinymceai_reviews`](#tinymceai_reviews) option.

**Default value:**

```js
[
  'ai-reviews-tone-casual',
  'ai-reviews-tone-direct',
  'ai-reviews-tone-friendly',
  'ai-reviews-tone-confident',
  'ai-reviews-tone-professional'
]
```
Example
```js
tinymce.init({
  selector: 'textarea',
  plugins: 'tinymceai',
  toolbar: 'tinymceai-chat tinymceai-quickactions tinymceai-review',
  tinymceai_reviews_change_tone_menu: [
    'ai-reviews-tone-professional',
    'ai-reviews-tone-friendly'
  ],
  // Required for authentication
  tinymceai_token_provider: () => {
    return fetch('/api/token').then(r => r.json());
  }
});
```

##### Integrator-defined reviews

In addition to the built-in review command IDs, the `tinymceai_reviews` option accepts integrator-defined review objects. These objects can be interleaved with the built-in string IDs, allowing integrators to add named reviews to the Review sidebar.

Each integrator-defined review object has a `type` of `'simple'`, `'list'`, or `'input'`, and shares the following properties:

- `type`: The review type. One of `'simple'`, `'list'`, or `'input'`.
- `id`: A unique identifier for the review. It must not reuse a built-in review command ID.
- `name`: The review name shown in the Review sidebar.
- `description`: A short description shown beneath the name.
- `prompt`: The prompt sent to the model when the review runs.
- `model` (optional): The model used for the review. The value must be a model ID that the configured AI service exposes (see [AI Models](../tinymceai-models/)). When omitted, the editor default model set by [`tinymceai_default_model`](#tinymceai_default_model) is used.

A `list` review adds an `options` array, and an `input` review adds an optional `inputPlaceholder`:

- `options` (`list` only): An array of `{ label, value }` objects. The selected `value` is substituted into the prompt wherever `{value}` appears.
- `inputPlaceholder` (`input`, optional): Placeholder text for the input field. TinyMCE substitutes the text entered by the end user into the prompt wherever `{input}` appears.

If an integrator-defined review is invalid, for example, if it reuses a built-in review command ID or does not match the expected schema, TinyMCE falls back to the default reviews list in the Review sidebar.

> **Note:** The `model` ID used in the following examples (`agent-1`) selects the recommended automatic model. The available model IDs depend on the configured AI service. See [AI Models](../tinymceai-models/) for the supported models and how to confirm which are available in an environment.
Simple integrator-defined review
```js
tinymceai_reviews: [
  {
    type: 'simple',
    id: 'integrator-simple-review',
    name: 'Simple Integrator Review',
    description: 'This is a simple integrator review',
    prompt: 'Review this document',
    model: 'agent-1'
  }
]
```
List integrator-defined review
```js
tinymceai_reviews: [
  {
    type: 'list',
    id: 'integrator-list-review',
    name: 'Translate Document',
    description: 'Translate the document to a selected language.',
    prompt: 'Translate this document to {value}',
    model: 'agent-1',
    options: [
      { label: 'English', value: 'english' },
      { label: 'Swedish', value: 'swedish' }
    ]
  }
]
```
Input integrator-defined review
```js
tinymceai_reviews: [
  {
    type: 'input',
    id: 'integrator-input-review',
    name: 'Custom Instruction',
    description: 'Apply a custom instruction.',
    prompt: 'Apply the following instruction {input}',
    model: 'agent-1',
    inputPlaceholder: 'Enter an instruction here...'
  }
]
```
Built-in and integrator-defined reviews combined
```js
tinymceai_reviews: [
  // Built-in reviews
  'ai-reviews-proofread',
  'ai-reviews-improve-clarity',
  'ai-reviews-change-tone',
  'ai-reviews-custom',
  // Integrator-defined review
  {
    type: 'simple',
    id: 'integrator-simple-review',
    name: 'Simple Integrator Review',
    description: 'This is a simple integrator review',
    prompt: 'Review this document',
    model: 'agent-1'
  }
]
```

## Toolbar buttons

The TinyMCE AI plugin provides the following toolbar buttons:

| Toolbar button identifier | Description |
| --- | --- |
| ![Chat icon](../_images/icons-premium/ai-assistant.svg) `tinymceai-chat` | Opens the AI Chat sidebar for conversations with the AI agent. |
| ![Quick Actions icon](../_images/icons/ai-prompt.svg) `tinymceai-quickactions` | Opens the AI Quick Actions menu (improve writing, fix grammar, translate, and similar). |
| ![Review icon](../_images/icons-premium/ai-review.svg) `tinymceai-review` | Opens the AI Review sidebar for running content review workflows. |

For submenu and individual action identifiers (for example, `ai-quickactions-improve-writing`, `ai-chat-explain`), see [Configuring Quick Actions menu](../tinymceai-actions/#configuring-quick-actions-menu).

These toolbar buttons can be added to the editor using:

- The [`toolbar`](../toolbar-configuration-options/#toolbar) configuration option.
- The [`quickbars_insert_toolbar`](../quickbars/#quickbars_insert_toolbar) configuration option.
- [Custom Context toolbars](../contexttoolbar/).

## Menu items

The TinyMCE AI plugin provides the following menu items:

| Menu item identifier | Default Menu Location | Description |
| --- | --- | --- |
| ![Chat icon](../_images/icons-premium/ai-assistant.svg) `tinymceai-chat` | Tools | Opens the AI Chat sidebar. |
| ![Quick Actions icon](../_images/icons/ai-prompt.svg) `tinymceai-quickactions` | Tools | Opens the AI Quick Actions menu. |
| ![Review icon](../_images/icons-premium/ai-review.svg) `tinymceai-review` | Tools | Opens the AI Review sidebar. |

For submenu and individual menu item identifiers (for example, `ai-quickactions-improve-writing`, `ai-chat-explain`), see [Configuring Quick Actions menu](../tinymceai-actions/#configuring-quick-actions-menu).

These menu items can be added to the editor using:

- The [`menu`](../menus-configuration-options/#menu) configuration option.
- The [`contextmenu`](../menus-configuration-options/#contextmenu) configuration option.
- [Custom Menu toolbar buttons](../custom-menu-toolbar-button/).

## Sidebars

The chat and review interfaces open as sidebars. From the toolbar or menu, clicking `tinymceai-chat`
![Chat icon](../_images/icons-premium/ai-assistant.svg)
opens the chat sidebar; clicking again minimizes it (chat history is preserved). Clicking `tinymceai-review`
![Review icon](../_images/icons-premium/ai-review.svg)
opens the review sidebar.

To toggle sidebars programmatically, use the core `ToggleSidebar` command:

```js
editor.execCommand('ToggleSidebar', false, 'tinymceai-chat');
editor.execCommand('ToggleSidebar', false, 'tinymceai-review');
```

### Keyboard shortcuts

The following keyboard shortcuts are available for the AI sidebars:

| Action | Windows | macOS |
| --- | --- | --- |
| Open or Close the AI Chat sidebar | Ctrl+J | Cmd+J |

To show the chat sidebar on load:

```js
tinymce.init({
  selector: 'textarea',  // change this value according to the HTML
  plugins: 'tinymceai',
  toolbar: 'tinymceai-chat tinymceai-quickactions tinymceai-review',
  sidebar_show: 'tinymceai-chat',
  // Required for authentication
  tinymceai_token_provider: () => {
    return fetch('/api/token').then(r => r.json());
  }
});
```

## Commands

The TinyMCE AI plugin provides the following TinyMCE commands.

## Toggling the AI Chat and AI Review sidebars

AI Chat and AI Review use sidebars registered by the plugin. To show or hide them programmatically, use the core `ToggleSidebar` command (listed in the [Miscellaneous Core Commands](../editor-command-identifiers/#miscellaneous-core-commands) table), not a command defined by the `tinymceai` plugin. Pass the sidebar identifier as the third argument:

- `'tinymceai-chat'` — AI Chat
- `'tinymceai-review'` — AI Review

Examples
```js
// Open the AI Chat sidebar
tinymce.activeEditor.execCommand('ToggleSidebar', false, 'tinymceai-chat');

// Close the current sidebar (pass the same ID again to toggle off)
tinymce.activeEditor.execCommand('ToggleSidebar', false, 'tinymceai-chat');

// Open the AI Review sidebar
tinymce.activeEditor.execCommand('ToggleSidebar', false, 'tinymceai-review');
```

> **Note:** These commands work regardless of [`tinymceai_sidebar_type`](#tinymceai_sidebar_type) (`'static'` or `'floating'`). The `ToggleSidebar` event and `queryCommandValue('ToggleSidebar')` also behave the same for both sidebar types.

## TinyMCE AI plugin commands

The [`tinymceai`](#) plugin registers the following editor commands. They mirror the Quick Actions, Chat, and Review user interface: each invocation returns immediately while the plugin performs any network and UI work asynchronously.

| Command | Third argument | Description |
| --- | --- | --- |
| `TinyMCEAIQuickActionImproveWriting` |  | Runs the **Improve writing** quick action. |
| `TinyMCEAIQuickActionContinueWriting` |  | Runs the **Continue writing** quick action. |
| `TinyMCEAIQuickActionCheckGrammar` |  | Runs the **Fix grammar** quick action. |
| `TinyMCEAIQuickActionMakeShorter` |  | Runs **Make shorter**. |
| `TinyMCEAIQuickActionMakeLonger` |  | Runs **Make longer**. |
| `TinyMCEAIQuickActionToneCasual` |  | Runs **More casual** tone. |
| `TinyMCEAIQuickActionToneDirect` |  | Runs **More direct** tone. |
| `TinyMCEAIQuickActionToneFriendly` |  | Runs **More friendly** tone. |
| `TinyMCEAIQuickActionToneConfident` |  | Runs **More confident** tone. |
| `TinyMCEAIQuickActionToneProfessional` |  | Runs **More professional** tone. |
| `TinyMCEAIQuickActionTranslate` | `string` | Runs **Translate** with the given language label (same string family as [`tinymceai_languages`](#tinymceai_languages) `language` values). |
| `TinyMCEAIQuickActionCustom` | `{ prompt, model }` | Runs a custom quick action with the given prompt and model (same behavior as [`tinymceai_quickactions_custom`](#tinymceai_quickactions_custom) preview actions). |
| `TinyMCEAIQuickActionsExplain` |  | Opens Chat with the built-in **Explain** prompt. |
| `TinyMCEAIQuickActionsSummarize` |  | Opens Chat with the built-in **Summarize** prompt. |
| `TinyMCEAIQuickActionsHighlightKeyPoints` |  | Opens Chat with the built-in **Highlight key points** prompt. |
| `TinyMCEAIChatPrompt` | `{ prompt, displayedPrompt? }` | Opens the Chat sidebar if needed, then sends `prompt` to the back end. Optional `displayedPrompt` controls the label shown in the chat UI when it differs from the text sent to the model. |
| `TinyMCEAIReviewProofread` |  | Runs the **Proofread** review. |
| `TinyMCEAIReviewClarity` |  | Runs the **Improve clarity** review. |
| `TinyMCEAIReviewReadability` |  | Runs the **Improve readability** review. |
| `TinyMCEAIReviewMakeLonger` |  | Runs the **Change length** review with the **Longer** option. |
| `TinyMCEAIReviewMakeShorter` |  | Runs the **Change length** review with the **Shorter** option. |
| `TinyMCEAIReviewToneCasual` |  | Runs the **Adjust tone and style** review with the **Casual** tone. |
| `TinyMCEAIReviewToneDirect` |  | Runs the **Adjust tone and style** review with the **Direct** tone. |
| `TinyMCEAIReviewToneFriendly` |  | Runs the **Adjust tone and style** review with the **Friendly** tone. |
| `TinyMCEAIReviewToneConfident` |  | Runs the **Adjust tone and style** review with the **Confident** tone. |
| `TinyMCEAIReviewToneProfessional` |  | Runs the **Adjust tone and style** review with the **Professional** tone. |
| `TinyMCEAIReviewCustom` | `String`, `{ prompt, model, name }`, or `{ id, value }` | Runs a review from a custom prompt, or runs an [integrator-defined review](#integrator-defined-reviews) by identifier. See [Values for `TinyMCEAIReviewCustom`](#tinymceai-review-custom-values). |

Each `TinyMCEAIReview…` command opens the Review sidebar and runs the review, with the same result as selecting that review in the sidebar. Running a review command while another review is in progress stops the earlier review and starts the requested one.

> **Note:** Command names use the `TinyMCEAIQuickActions…` prefix (with an `s`) for **Explain**, **Summarize**, and **Highlight key points** — these map to the [chat prompts](#tinymceai_quickactions_chat_prompts) submenu, not to standalone `TinyMCEAIQuickAction…` spellings.
Example: translate and custom quick action
```js
tinymce.activeEditor.execCommand('TinyMCEAIQuickActionTranslate', false, 'swedish');

tinymce.activeEditor.execCommand('TinyMCEAIQuickActionCustom', false, {
  prompt: 'Uppercase text',
  model: 'gpt-4.1'
});
```
Example: chat prompt with a shorter label in the UI
```js
tinymce.activeEditor.execCommand('TinyMCEAIChatPrompt', false, {
  prompt: 'Explain the current selection in Klingon',
  displayedPrompt: 'Explain'
});
```
Example: running built-in reviews
```js
tinymce.activeEditor.execCommand('TinyMCEAIReviewProofread');

tinymce.activeEditor.execCommand('TinyMCEAIReviewToneProfessional');
```

### Values for `TinyMCEAIReviewCustom`

The `TinyMCEAIReviewCustom` command accepts three forms of third argument.

A `String` runs a review from that prompt on the default model, titled **Custom review**:

```js
tinymce.activeEditor.execCommand('TinyMCEAIReviewCustom', false, 'Check for passive voice');
```
An object with a `prompt` property runs a review from a custom prompt:

- `prompt` (`String`): The prompt sent to the model. This property is required.
- `model` (optional `String`): The model that runs the review. When omitted, the review runs on the model set by [`tinymceai_default_model`](#tinymceai_default_model). For the available model identifiers, see [AI Models](../tinymceai-models/).
- `name` (optional `String`): The title shown above the review. When omitted, the title is **Custom review**.

```js
tinymce.activeEditor.execCommand('TinyMCEAIReviewCustom', false, {
  prompt: 'Check the document for passive voice',
  model: 'agent-1',
  name: 'Passive voice'
});
```
An object with an `id` property runs an [integrator-defined review](#integrator-defined-reviews) configured in [`tinymceai_reviews`](#tinymceai_reviews):

- `id` (`String`): The `id` of the integrator-defined review. This property is required.
- `value` (optional `String`): The value passed to the review. A `simple` review takes no value. For a `list` review, the value must match one of the review’s `options` values; when omitted, the first option is used. For an `input` review, the value is the text substituted into the prompt, and it is required.

```js
tinymce.activeEditor.execCommand('TinyMCEAIReviewCustom', false, {
  id: 'integrator-list-review',
  value: 'swedish'
});
```
When the value does not match any of these forms, TinyMCE logs an error to the browser console and runs no review. This also applies when the prompt or identifier is blank, when no integrator-defined review matches the identifier, when a `list` review value is not one of its options, and when an `input` review is run without a value.
