---
title: "Revision History Plugin"
description: "A view that allows TinyMCE users to see historical snapshots of a document and an ability to restore from a snapshot"
canonical_url: "https://www.tiny.cloud/docs/tinymce/latest/revisionhistory/"
md_url: "https://www.tiny.cloud/docs/tinymce/7/revisionhistory/index.md"
version: "7"
last_updated: "2025-02-20T08:38:42Z"
tokens: 5748
---
Important This page documents TinyMCE 7. For new projects, Tiny recommends using the latest, most up-to-date version. [See TinyMCE 8 documentation](../../latest/revisionhistory/).
# Revision History Plugin

> **Note:** This plugin is only available as a [paid add-on](/tinymce/features/revision-history/) to [a TinyMCE subscription](/pricing/).

> **Note:** This feature is only available for TinyMCE 7.0 and later.
The Revision History plugin offers users the ability to view document changes over time and restore previous revisions effortlessly.

## Interactive example

**Example**

```js
const API_URL = 'https://demouserdirectory.tiny.cloud/v1/users';
const fakeDelay = 200;

const revisions = [
  {
    revisionId: '3',
    createdAt: '2023-11-24T22:26:21.578Z',
    author: {
      id: 'james-wilson',
      name: 'James Wilson',
      avatar: 'https://sneak-preview.tiny.cloud/demouserdirectory/images/employee_james-wilson_128_52f19412.jpg',
    },
    content: `
      <p><img style="display: block; margin-left: auto; margin-right: auto;" title="Tiny Logo" src="https://www.tiny.cloud/docs/tinymce/latest/_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>
      <h2>A simple table to play with</h2>
      <table style="border-collapse: collapse; width: 100%;" border="1">
      <thead>
      <tr>
      <th>Product</th>
      <th>Cost</th>
      <th>Really?</th>
      </tr>
      </thead>
      <tbody>
      <tr>
      <td style="text-align: center;">TinyMCE</td>
      <td style="text-align: center;">Free</td>
      <td style="text-align: center;">YES!</td>
      </tr>
      </tbody>
      </table>
      <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><s>Need file uploads in your app? Consider using <a href="https://www.tiny.cloud/docs/tinymce/7/uploadcare/" target="_blank" rel="noopener noreferrer">Uploadcare</a> with TinyMCE for a fast, modern upload experience.</s></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>
    `,
  },
  {
    revisionId: '2',
    createdAt: '2023-11-25T08:30:21.578Z',
    author: {
      id: 'mia.andersson',
      name: 'Mia Andersson',
      avatar: 'https://sneak-preview.tiny.cloud/demouserdirectory/images/employee_mia-andersson_128_e6f9424b.jpg',
    },
    content: `
      <p><img style="display: block; margin-left: auto; margin-right: auto;" title="Tiny Logo" src="https://www.tiny.cloud/docs/tinymce/latest/_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>
      <h2>Got questions or need help?</span></h2>
      <ol>
      <li>Our <a href="../">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="../../../../pricing">TinyMCE premium plans</a>.</li>
      </ol>
      <h2>A simple table to play with</h2>
      <table style="border-collapse: collapse; width: 100%;" border="1">
      <thead>
      <tr>
      <th>Product</th>
      <th>Cost</th>
      <th>Really?</th>
      </tr>
      </thead>
      <tbody>
      <tr>
      <td style="text-align: center;">TinyMCE</td>
      <td style="text-align: center;">Free</td>
      <td style="text-align: center;">YES!</td>
      </tr>
      </tbody>
      </table>
      <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>Need file uploads in your app? Consider using <a href="https://www.tiny.cloud/docs/tinymce/7/uploadcare/" target="_blank" rel="noopener noreferrer">Uploadcare</a> with TinyMCE for a fast, modern upload experience.</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>
    `,
  },
  {
    revisionId: '1',
    createdAt: '2023-11-29T10:11:21.578Z',
    author: {
      id: 'mia.andersson',
      name: 'Mia Andersson',
      avatar: 'https://sneak-preview.tiny.cloud/demouserdirectory/images/employee_mia-andersson_128_e6f9424b.jpg',
    },
    content: `
      <p><img style="display: block; margin-left: auto; margin-right: auto;" title="Tiny Logo" src="https://www.tiny.cloud/docs/tinymce/latest/_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>
      <h2>Got questions or need help?</h2>
      <ul>
      <li>Our <a href="../">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="../../../../pricing">TinyMCE premium plans</a>.</li>
      </ul>
      <h2>A simple table to play with</h2>
      <table style="border-collapse: collapse; width: 100%;" border="1">
      <thead>
      <tr>
      <th>Product</th>
      <th>Cost</th>
      <th>Really?</th>
      </tr>
      </thead>
      <tbody>
      <tr>
      <td style="text-align: center;">TinyMCE</td>
      <td style="text-align: center;">Free</td>
      <td style="text-align: center;">YES!</td>
      </tr>
      </tbody>
      </table>
      <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>Need file uploads in your app? Consider using <a href="https://www.tiny.cloud/docs/tinymce/7/uploadcare/" target="_blank" rel="noopener noreferrer">Uploadcare</a> with TinyMCE for a fast, modern upload experience.</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>
    `,
  }
];

const revisionhistory_fetch = () => new Promise((resolve) => {
  setTimeout(() => {
    const sortedRevisions = revisions
      .sort((a, b) => new Date(a.createdAt) < new Date(b.createdAt) ? -1 : 1);
    resolve(sortedRevisions);
  }, fakeDelay);
});

const revisionhistory_fetch_revision = (_editor, revision) => new Promise((resolve, reject) => {
  setTimeout(() => {
    const revision = revisions.find((r) => r.revisionId === revision.revisionId);
    if (revision) {
      resolve(revision);
    } else {
      reject(`Revision ${revision.revisionId} is not found`);
    }
  }, fakeDelay);
});

tinymce.init({
  selector: 'textarea#revisionhistory',
  height: 800,
  plugins: 'revisionhistory help code link lists image',
  toolbar: 'undo redo | styles | bold italic underline | revisionhistory | link image | code',
  content_style: 'body { font-family:Helvetica,Arial,sans-serif; font-size:16px }',
  revisionhistory_fetch,
  revisionhistory_fetch_revision,
  revisionhistory_display_author: true,
  revisionhistory_author: {
    id: 'james-wilson',
    name: 'James Wilson',
    avatar: 'https://sneak-preview.tiny.cloud/demouserdirectory/images/employee_james-wilson_128_52f19412.jpg',
  },
});
```

> **Note:** This feature is only supported when TinyMCE is run in *classic* mode. It is not supported in *inline* mode. For more information on the differences between the editing modes, see [Classic editing mode](../use-tinymce-classic/).

## How it works

The Revision History view is accessible via either the `revisionhistory` toolbar button or menu button within the `View` menu.

The key components are:

1. In the Revision History view header, there are two buttons.

  - `Restore this version`: Sets the selected revision’s content to the editor and closes the view. Note: the button is disabled for the `initial` and `draft` revisions.
  - `Close`: Closes the **Revision History** view.
2. The readonly diff view presents the changes between the selected revision and its immediate predecessor, clearly highlighting for easy recognition. The changes are also color-coded for clarity:

  - Red: Removed content.
  - Green: New content.
  - Yellow: Content being modified. Modifications to HTML content implies attributes or formatting (e.g. bold, italic, etc.).
3. The revisions sidebar displays all available document revisions. When a revision is selected, the diff view is updated accordingly.

> **Note:** The default highlighting colors can be customized using the [`revisionhistory_css_url`](#revisionhistory_css_url) option.

> **Note:** The Revision History plugin processes commented HTML as valid content but disregards it during the revision comparison process. Revisions containing only commented content appear as empty in the view.

## Basic setup

To setup the Revision History plugin in the editor:

- add `revisionhistory` to the `plugins` option in the editor configuration;
- add `revisionhistory` to the `toolbar` option in the editor configuration;
- add `revisionhistory_fetch` option to the editor configuration;

For example:

```js
tinymce.init({
  selector: 'textarea',  // change this value according to your HTML
  plugins: 'revisionhistory',
  toolbar: 'revisionhistory',
  revisionhistory_fetch: () => Promise.resolve([]), // Replace this with an API request to get saved revisions
});
```

## Understanding revision types

The Revision History plugin offers three revision types:

1. **Initial**: This revision is generated during the TinyMCE `Loaded` event, capturing the editor’s initial content.
2. **Draft**: Generated upon opening the Revision History, this revision reflects the editor’s current content. When included, it becomes the `latest revision` in the revisions list.
3. **Saved**: These revisions are fetched from the client’s storage when opening the Revision History view, using the `revisionhistory_fetch` and `revisionhistory_fetch_revision` options.

When working with a document that has no saved revisions, the Revision History plugin typically maintains two revisions: `initial` and `draft`. If no changes have been made to the content since initialization, the `initial` revision is not displayed, as it is identical to the `draft` revision.

For documents with saved revisions, the `initial` revision is disregarded, assuming it already exists among the saved revisions. To include the initial content, add it as a revision using the `revisionhistory_fetch` option.

## Data structure

### Revision

The revision is an `Object` that contains the following fields:

| Field | Type | Required? | Description |
| --- | --- | --- | --- |
| `revisionId` | `string` | required | The unique string ID of the revision. |
| `createdAt` | `string` | required | A UTC datetime string in ISO-8061 format. |
| `content` | `string` | optional | HTML string of the revision content. Empty string is considered as valid content. |
| `author` | [Author](#author) `Object` | optional | The author of the revision. |

### Author

The author is an `Object` that represents the author or creator of a revision. It contains the following fields:

| Field | Type | Required? | Description |
| --- | --- | --- | --- |
| `id` | `string` | required | The unique string ID of the author. |
| `name` | `string` | optional | The name of the revision author. If not provided, the default value is `Anonymous`. |
| `avatar` | `string` | optional | The URL of the author’s avatar image. If not provided or invalid, the Revision History will use a generated avatar using the author’s initials. |

## Options

The following configuration options affect the behavior of the Revision History plugin.

### `revisionhistory_fetch`

The `revisionhistory_fetch` function retrieves saved revisions and is called when the user opens the Revision History view.

> **Important:** The `revisionhistory_fetch` function is required for the Revision History plugin to function.
It expects an asynchronous function that returns a [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) which resolves to an array of revisions.

> **Note:** The Revision History plugin does not sort results before displaying them, allowing integrators to sort the results according to their preference. Tiny recommends to sort the results in reverse chronological order, as this makes it easier for users to identify revisions by date.
**Type:** `Function` (Returns a [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise))

**Input parameters:** None

**Return data:** `Array` of [Revision](#revision) `Objects`

#### Example of `revisionhistory_fetch` response

```js
const revisions = [
  {
    revisionId: '3',
    createdAt: '2023-11-29T10:11:21.578Z',
    content: `
      <h2>Welcome to TinyMCE Docs!</h2>
      <p>Here is some content that is <strong>bold</strong> and <em>italic</em>.</p>
    `,
  },
  {
    revisionId: '2',
    createdAt: '2023-11-25T08:30:21.578Z',
    content: `
      <p>Welcome to TinyMCE Docs!</p>
      <p>Here is some content that is bold and italic.</p>
    `,
  },
  {
    revisionId: '1',
    createdAt: '2023-11-24T22:26:21.578Z',
    content: `
      <p>Welcome to Tinymce!</p>
    `,
  }
];
```

#### Example: Using `revisionhistory_fetch`

```js
tinymce.init({
  selector: 'textarea',  // change this value according to your HTML
  plugins: 'revisionhistory',
  toolbar: 'revisionhistory',
  revisionhistory_fetch: () =>
    fetch('<API URL>')  // Update the URL and response handling code according to your API
    .then((response) => response.json())
    .then((data) => data)
    .catch((error) => console.log('Failed to get revisions\n' + error))
});
```

### `revisionhistory_fetch_revision`

When a revision is selected, the plugin uses this option to update the selected or closest revision that has no content. The function is expected to return a Promise that resolves with an updated revision.

**Type:** `Function` (Returns a [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise))

**Input parameters:**

| Field | Type | Required? | Description |
| --- | --- | --- | --- |
| `editor` | `Editor` | required | The current editor instance (useful if there are multiple editors on the page). |
| `revision` | [Revision](#revision) `Object` | required | The targeted revision. |

**Return data:** [Revision](#revision) `Object`

#### Example: Using `revisionhistory_fetch_revision`

```js
const lightRevisions = [
  {
    revisionId: '3',
    createdAt: '2023-11-29T10:11:21.578Z',
  },
  {
    revisionId: '2',
    createdAt: '2023-11-25T08:30:21.578Z',
  },
  {
    revisionId: '1',
    createdAt: '2023-11-24T22:26:21.578Z',
  }
];

const revisions = [
  {
    revisionId: '3',
    createdAt: '2023-11-29T10:11:21.578Z',
    content: `
      <h2>Welcome to TinyMCE Docs!</h2>
      <p>Here is some content that is <strong>bold</strong> and <em>italic</em>.</p>
    `,
  },
  {
    revisionId: '2',
    createdAt: '2023-11-25T08:30:21.578Z',
    content: `
      <p>Welcome to TinyMCE Docs!</p>
      <p>Here is some content that is bold and italic.</p>
    `,
  },
  {
    revisionId: '1',
    createdAt: '2023-11-24T22:26:21.578Z',
    content: `
      <p>Welcome to Tinymce!</p>
    `,
  }
];

tinymce.init({
  selector: 'textarea',  // change this value according to your HTML
  plugins: 'revisionhistory',
  toolbar: 'revisionhistory',
  revisionhistory_fetch: () => Promise.resolve(lightRevisions),
  revisionhistory_fetch_revision: (_editor, revision) => new Promise((resolve) => {
  let newRevision = null;
  for (let i = 0; i < revisions.length; i++) {
    const temp = revisions[i];
    if (temp.revisionId === revision.revisionId) {
      newRevision = temp;
      break;
    }
  }
  resolve(newRevision);
  })
});
```

### `revisionhistory_allow_restore`

The `revisionhistory_allow_restore` option enables or disables the ability to restore a revision.

**Type:** `Boolean`

**Default vale:** `true`

#### Example: Using `revisionhistory_allow_restore`

```js
tinymce.init({
  selector: 'textarea',  // change this value according to your HTML
  plugins: 'revisionhistory',
  toolbar: 'revisionhistory',
  revisionhistory_fetch: () => Promise.resolve([]), // Required option for the plugin - replace with actual API request
  revisionhistory_allow_restore: false
  });
```

### `revisionhistory_author`

This option configures the author for the `initial` and `draft` revisions.

**Type:** [Author](#author) `Object`

#### Example: using `revisionhistory_author`

```js
tinymce.init({
  selector: 'textarea',  // Change this value according to your HTML
  plugins: 'revisionhistory',
  toolbar: 'revisionhistory',
  revisionhistory_fetch: () => Promise.resolve([]),
  revisionhistory_display_author: true,
  revisionhistory_author: {
    id: 'john.doe',
    name: 'John Doe',
    avatar: 'https://example.com/avatar.jpg'
  }
});
```

### `revisionhistory_display_author`

This option configures the display of the revision’s author. When set to `true`, the author’s name appears in each revision within the Revision History sidebar. If the author’s name is not provided, it defaults to `Anonymous`.

**Type:** `Boolean`

**Default value:** `false`

#### Example: using `revisionhistory_display_author`

```js
tinymce.init({
  selector: 'textarea',  // Change this value according to your HTML
  plugins: 'revisionhistory',
  toolbar: 'revisionhistory',
  revisionhistory_fetch: () => Promise.resolve([]),
  revisionhistory_display_author: true
});
```

### `revisionhistory_css_url`

This option sets the location where a CSS file containing the styles for change annotations should be loaded from. It can be used along with `revisionhistory_diff_classes` to override the default CSS classes.

> **Note:** Ensure that the file includes all CSS classes expected by [`revisionhistory_diff_classes`](#revisionhistory_diff_classes).
**Type:** `String`

**Default value:** `'${pluginUrl}/css/revisionhistory.css'`

#### Example: using `revisionhistory_css_url`

```js
tinymce.init({
  selector: 'textarea',  // change this value according to your HTML
  plugins: 'revisionhistory',
  toolbar: 'revisionhistory',
  revisionhistory_fetch: () => Promise.resolve([]), // Required option for the plugin - replace with actual API request
  revisionhistory_css_url: './revisionhistory.css'
});
```

### `revisionhistory_diff_classes`

This option configures the CSS classes being applied to the change annotations. This option can be used in combination with the `revisionhistory_css_url` to provide custom styles to the change annotations.

> **Note:** The CSS class names must exist in the [`revisionhistory_css_url`](#revisionhistory_css_url).
**Type:** `Object`

**Default value:** `addition`, `removal`, `modification`

```js
{
  addition: 'tox-revisionhistory__annotation--added',
  removal: 'tox-revisionhistory__annotation--removed',
  modification: 'tox-revisionhistory__annotation--modified'
}
```

#### Example: using `revisionhistory_diff_classes`

```js
tinymce.init({
  selector: 'textarea',  // change this value according to your HTML
  plugins: 'revisionhistory',
  toolbar: 'revisionhistory',
  revisionhistory_fetch: () => Promise.resolve([]), // Required option for the plugin - replace with actual API request
  revisionhistory_css_url: './revisionhistory.css',
  revisionhistory_diff_classes: {
    addition: 'added',
    removal: 'removed',
    modification: 'modified'
  }
});
```

## Toolbar buttons

The Revision History plugin provides the following toolbar buttons:

| Toolbar button identifier | Description |
| --- | --- |
| `revisionhistory` | Opens the Revision History view. |

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 Revision History plugin provides the following menu items:

| Menu item identifier | [Default Menu Location](../menus-configuration-options/#example-the-tinymce-default-menu-items) | Description |
| --- | --- | --- |
| `revisionhistory` | View | Opens the Revision History view. |

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/).

## Commands

The Revision History plugin provides the following TinyMCE commands.

| Command | Description |
| --- | --- |
| revisionHistory | Toggle the Revision History view |

Examples
```js
tinymce.activeEditor.execCommand('revisionHistory');
```

## Events

The Revision History plugin provides the following events.

The following events are provided by the [Revision History plugin](#).

| Name | Data | Description |
| --- | --- | --- |
| VersionRestored | `{ revisionId: string }` | Fired when a version is restored. |

## APIs

The Revision History plugin provide the following APIs.

```ts
interface PluginAPI {
  diff: (originalHTML: string, changedHTML: string) => string
}
```

### `diff`

Returns a HTML string with annotations indicating the changes in `originalHTML` relative to `changedHTML`. The styling of annotations can be customized via [`revisionhistory_diff_classes`](#revisionhistory_diff_classes) option.

> **Note:** This feature is only available for TinyMCE 7.1 and later.
Example
```js
const input1 = `<p>The banner is <span style="color: rgb(224, 62, 45);">red</span></p>`;
const input2 = `<p>The flag is <span style="color: rgb(22, 145, 121);">red</span></p>`;
tinymce.activeEditor.plugins.revisionhistory.diff(input1, input2);
/*
Expected output:
<p>The
 <del class="tox-revisionhistory__annotation--removed">banner</del><ins class="tox-revisionhistory__annotation--added">flag</ins>
 is
<ins class="tox-revisionhistory__annotation--modified"><span style="color: rgb(22, 145, 121);">red</span></ins>
</p>
*/
```
