---
title: "Configuring custom dialogs"
description: "How to create a basic dialog for TinyMCE."
canonical_url: "https://www.tiny.cloud/docs/tinymce/latest/dialog-configuration/"
md_url: "https://www.tiny.cloud/docs/tinymce/6/dialog-configuration/index.md"
version: "6"
last_updated: "2023-11-30T00:15:30Z"
tokens: 3612
---
Important This page documents TinyMCE 6. For new projects, Tiny recommends using the latest, most up-to-date version. [See TinyMCE 8 documentation](../../latest/dialog-configuration/).
# Configuring custom dialogs

A dialog configuration has three main parts to match the three main parts of a dialog’s UI.

1. **Title**

  - the dialog’s title.
  - It displays in the dialog’s header.
2. **Body**

  - the dialog’s body.
  - The body component can be a [panel](../dialog-components/#panel) or a [tab panel](../dialog-components/#tabpanel), which can contain an array of [panel components](../dialog-components/#panel-components) such as buttons, inputs and text.
3. **Buttons**

  - An array of [footer buttons](../dialog-footer-buttons/) that are displayed in the dialog’s footer.

## Basic example

The configuration for a basic dialog that displays HTML information might look like this:

```js
tinymce.activeEditor.windowManager.open({
  title: 'Dialog Title', // The dialog's title - displayed in the dialog header
  body: {
    type: 'panel', // The root body type - a Panel or TabPanel
    items: [ // A list of panel components
      {
        type: 'htmlpanel', // an HTML panel component
        html: 'Panel content goes here.'
      }
    ]
  },
  buttons: [ // A list of footer buttons
    {
      type: 'submit',
      text: 'OK'
    }
  ]
});
```

## Options

| Name | Value | Requirement | Description |
| --- | --- | --- | --- |
| title | string | required | The title of the dialog. This will display in the header of the dialog. |
| body | `panel` or `tabpanel` component | required | The specification for the [body component](../dialog-components/). |
| buttons | `FooterButton[]` | required | An array of [footer buttons](../dialog-footer-buttons/) to render in the footer of the dialog. |
| size | `'normal'`, `'medium'` or `'large'` | optional | default: `normal`. `normal` sets the dialog to be responsive to the viewport size. `medium` sets the dialog to render with only the height required to fits its components. `large` sets the dialog to a large fixed height. `inline` dialogs do not support `size: 'large'`. |
| initialData | object | optional | An object containing initial values for the dialog’s panel components. |
| onAction | `(dialogApi, details) => void` | optional | Function invoked when a user interacts with a `button` type panel component, clicks a **Custom** type footer button, or clicks an item in a **Menu** type footer button. |
| onSubmit | `(dialogApi) => void` | optional | Function invoked when a **Submit** type footer button is clicked. |
| onCancel | `(dialogApi) => void` | optional | Function invoked when the dialog is cancelled. The dialog header’s close button and a **Cancel** type footer button invoke this function. |
| onChange | `(dialogApi, details) => void` | optional | Function invoked when the value of an `input` type panel component changes. |
| onClose | `() => void` | optional | Function invoked when the dialog is closed. The dialog header’s close button, a **Cancel** type footer button and the dialog instance API’s `close()` method invoke this function. |
| onTabChange | `(dialogApi, details) => void` | optional | **This method only applies to [tab panel](../dialog-components/#tabpanel) dialogs.** Function invoked when the user changes tabs. `details` is an object that contains `newTabName` and `oldTabName`. |

For more information on the `dialogApi` object that is passed to some of the configuration options, see the [dialog instance API](../dialog-components/#dialog-instance-api-methods) documentation.

### Event callback functions

Each of the event callback functions - `onAction`, `onSubmit`, `onCancel`, `onChange`, `onClose`, and `onTabChange` - are shared between all dialog components that may trigger them. For example, **Custom** type footer buttons and dialog panel buttons all trigger `onAction`. Therefore, callback functions that may be triggered by multiple components are passed an object (called `details` above) that contains the `name` of the component that triggered the event.

Any callback function that is not passed a `details` object assumes that the dialog will only contain one component which can trigger it or that it does not matter if the function is triggered by multiple components. For example, `onSubmit` is only triggered when a user clicks on a **Submit** type footer button, and TinyMCE assumes that a dialog will only have one **Submit** type button. In comparison, `onCancel` and `onClose` are both triggered by clicking the `X` button in the top right of a dialog or by clicking a **Cancel** type footer button. These two buttons have the same functionality, and therefore TinyMCE does not differentiate between them.

## Configuration parameters

### `align`

> **Note:** This feature is only available for TinyMCE 6.6 and later.
`align` is an optional property to add to dialog labels to set the alignment of the label text.

The property has a default value of `start`.

This is also the value applied if the property is not explicitly set.

**Type:** `String`

**Possible values:** `'+start+'`, `'+center+'`, `end`

**Default value:** `start`

The values, `start` and `end`, refer to the beginning or end of a text line and are relative to the display language.

For left-to-right written languages (eg English or Vietnamese), `start` sets the dialog label as left-aligned and `end` sets the dialog label as right-aligned.

For right-to-left written languages (eg Arabic or Persian), `start` sets the dialog label as right-aligned and `end` sets the dialog label as left-aligned.

### Example: using `align` to set a dialog caption as end-aligned

```js
tinymce.activeEditor.windowManager.open({
  title: 'Dialog Title', // The dialog's title - displayed in the dialog header
  body: {
    type: 'panel', // The root body type - a Panel or TabPanel
    items: [
        {
          type: 'label', // component type
          label: 'Caption', // text for the group label
          align: 'end',
          items: [
            {
              type: 'htmlpanel', // an HTML panel component
              html: 'Panel content goes here.'
            }
          ]
        }
    ]
  },
  buttons: [ // A list of footer buttons
    {
      type: 'submit',
      text: 'OK'
    }
  ]
});
```

### `border`

> **Note:** This feature is only available for TinyMCE 6.6 and later.
`border` is an optional property, available to add to the `iframe` dialog component.

The property has a default value of `false`.

When this property is set to `true`, a border displays around the `iframe` component.

The border is also highlighted when the `iframe` component takes focus (by, for example, using the Tab key to change focus within the active dialog).

**Type:** `Boolean`

**Possible values:** `true`, `false`

**Default value:** `false`

### Example: using `border` to display a border around an `iframe` component

```js
tinymce.activeEditor.windowManager.open({
  title: 'Dialog Title', // The dialog's title - displayed in the dialog header
  body: {
    type: 'panel', // The root body type - a Panel or TabPanel
    items: [ // A list of panel components
      {
        name: 'preview',
        type: 'iframe',
        border: true,
      }
    ]
  },
  buttons: [ // A list of footer buttons
    {
      type: 'submit',
      text: 'OK'
    }
  ]
});
```

### Using `buttons` to configure a dialog without a footer

> **Note:** This feature is only available for TinyMCE 6.6 and later.
In addition to its usual functions, the `buttons` property can also be used to stop the footer section from displaying.

To configure a custom dialog so it does not render a footer section when displayed, set the `buttons` property to an empty array, `[]`, or omit it entirely.

### basic example of a dialog without buttons or a footer

```js
tinymce.activeEditor.windowManager.open({
  title: 'Dialog Title', // The dialog's title - displayed in the dialog header
  body: {
    type: 'panel', // The root body type - a Panel or TabPanel
    items: [ // A list of panel components
      {
        type: 'htmlpanel', // an HTML panel component
        html: 'Panel content goes here.'
      }
    ]
  },
  buttons: []
});
```

### `persistent`

> **Note:** This feature is only available for TinyMCE 6.6 and later.
The `persistent` property, when set to `true`, allows an inline dialog to stay open when the dialog no longer has focus.

If an end-user gives another part of the TinyMCE editor focus (for example, the document editor, or a menu), the inline dialog will stay open.

Setting the property to `true` does not over-ride normal mechanisms for closing a dialog, such as clicking the *Close* button or pressing the **Esc** key.

The property has a default value of `false`.

> **Note:** If an inline dialog is open and focus is switched away from the TinyMCE editor entirely (by, for example, the end-user switching focus to an available host-browser UI element), an open inline dialog will remain open regardless of the `persistent` property’s value. This was the behavior prior to this property being available and continues to be the behavior.
**Type:** `Boolean`

**Possible values:** `true`, `false`

**Default value:** `false`

### Example: using `persistent`

```js
tinymce.activeEditor.windowManager.open({
  title: 'Dialog Title', // The dialog's title - displayed in the dialog header
  body: {
    type: 'panel', // The root body type - a Panel or TabPanel
    items: [ // A list of panel components
      {
        type: 'htmlpanel', // an HTML panel component
        html: 'Panel content goes here.'
      }
    ]
  },
  buttons: [ // A list of footer buttons
    {
      type: 'submit',
      text: 'OK'
    }
  ]},
  { inline: 'toolbar', persistent: true }
});
```

### Example: using `focus` to refocus an open but de-focused dialog

Because a dialog with a `{ persistent: true }` property does not close when the dialog loses focus, it is possible for an end-user to open a further instance of the dialog.

To prevent this

- add a check that the dialog is already open; and
- use the `focus` method in the [`DialogInstanceAPI`](../apis/tinymce.windowmanager/#open) to transfer focus to the open dialog rather than creating a new instance of the same dialog.

```js
let dialogOpened = false;
let dialogInstanceApi = null;

const openDialog = () => {
  dialogOpened = true;
  dialogInstanceApi = editor.windowManager.open({
    title: 'Test',
    body: {
      type: 'panel',
      items: [{
        type: 'bar',
        items: [{
            type: 'input',
            name: 'name',
            placeholder: 'Name',
            maximized: true
          }
        ]
      }]
    },
    onClose: () => {
      dialogOpened = false;
    },
    buttons: [{
      type: 'cancel',
      name: 'cancel',
      text: 'Cancel'
    }],
    initialData: {
      name: ''
    }
  }, {
    inline: 'bottom',
    persistent: true
  });
};

const focusDialog = () => {
  dialogInstanceApi.focus('name');
}

editor.ui.registry.addButton('example', {
  type: 'button',
  text: 'example',
  tooltip: 'example',
  onAction: () => {
    dialogOpened ? focusDialog() : openDialog();
  }
});
```

## `streamContent`

`streamContent` is an optional property, available to add to the `iframe` dialog component.

The property has a default value of `false`.

When `streamContent` is set to `true`, content presented within the `iframe` dialog component is updated using the `document.write()` method, rather than by setting the `srcdoc` attribute.

Setting the `srcdoc` attribute causes the `iframe` to reload. This results in a visually jarring flickering effect in most modern browsers, particularly when content is rapidly updating.

As well, performing updates via the `srcdoc` attribute means the contents of the `iframe` are not accessible. As a consequence, it is not possible to automatically scroll the `iframe` contents to the bottom as it gets updated.

Setting `streamContent` to `true` minimises the flickering effect.

If the `iframe` component is already scrolled to the end, `streamContent: true` also keeps the view at this point. The UX is content being added to the `iframe` component as if it is being quickly typed in.

A user can, however, scroll through the `iframe` component as updates are being added. If the view is scrolled back to the end while updates are still being added, the `streamContent: true` setting will, again, keep the view at this point.

**Type:** `Boolean`

**Possible values:** `true` `false`

**Default value:** `false`

### Example: setting an `iframe` component to display updating content using the `streamContent` property

```js
tinymce.activeEditor.windowManager.open({
  title: 'Dialog Title', // The dialog's title - displayed in the dialog header
  size: 'normal',
  body: {
    type: 'panel', // The root body type - a Panel or TabPanel
    items: [ // A list of panel components
      {
        name: 'preview',
        type: 'iframe',
        streamContent: true
      }
    ]
    },
    buttons: [ // A list of footer buttons
      {
        type: 'submit',
        text: 'OK'
      }
    ]
}, { inline: 'bottom' } );
```

> **Note:** Dialog position The example above also adds a second argument — `{ inline: 'bottom' } — to the dialog. This argument changes the presented position of the dialog within the TinyMCE editor.
> 
> For information on using this property see the [Dialog position](#dialog-position) section of the [Dialog configuration documentation](#).

### Recommended method for updating content in an `iframe` component

The recommended method for updating content in an `iframe` component is:

```js
`onAction: (api) => api.setData({ myiframe: 'new content' })`
```

1. This updates the iframe to contain the string `'new content'`. This text can be any valid html.
2. `onAction` is a callback defined in the dialog spec. It is called when a button within the dialog `body` is triggered.
3. `myiframe` is the name of the `iframe` component in this spec.

## Dialog position

By default a dialog is shown as a modal in the center of the editor viewport.

This presented position can be changed by providing a second argument, with an appropriate value, to [`editor.windowManager.open()`](../apis/tinymce.windowmanager/#open).

### `inline`

The `inline` option, passed to `editor.windowManager.open()`, sets the dialog’s presented position to one of two possiblities.

When added to a configuration with the value, `toolbar`, it sets the dialog to appear adjacent to the TinyMCE toolbar.

When added to a configuration with the value, `bottom`, it sets the dialog to appear at the bottom of the editor viewport.

**Type:** `String`

**Possible values:** `toolbar`, `bottom`

### Basic example with the inline argument added and set to toolbar

```js
tinymce.activeEditor.windowManager.open({
  title: 'Dialog Title', // The dialog's title - displayed in the dialog header
  body: {
    type: 'panel', // The root body type - a Panel or TabPanel
    items: [ // A list of panel components
      {
        type: 'htmlpanel', // an HTML panel component
        html: 'Panel content goes here.'
      }
    ]
  },
  buttons: [ // A list of footer buttons
    {
      type: 'submit',
      text: 'OK'
    }
  ]
}, { inline: 'toolbar' });
```
