Report an issue

Track changes overview

This feature enables the track changes mode (also known as the suggestion mode) in CKEditor 5. This way you can follow the history of changes made by different editors as well as easily accept or decline such changes.

Unlock this feature with a CKEditor Paid Plan. Sign up for a free trial, or select the Plan that provides access to all the premium features you need.

# Demo

You can test the track changes feature in the editor below. Use the toolbar dropdown Track changes to enable changes tracking and mass accept or decline suggestions. Use the side panel to work with individual changes.

This demo presents a limited set of features. Visit the feature-rich editor example to see more in action.

In this mode, changes done by the users are marked in the content and shown as suggestions in the sidebar. Suggestions can be accepted or discarded by the users. The suggestion balloon is then closed and the change is no longer marked.

Suggestion annotations can be displayed in a sidebar or as inline balloons. Visit the display mode guide to learn how to configure the display mode. The mode specified for comments is also set for track changes.

This sample automatically switches between display modes according to the screen size. Resize the window and observe how the editor changes its appearance.

Apart from reading this guide, we encourage you to read a dedicated blog post which compares the track changes with revision history and another blog post discussing CKEditor 5’s collaboration features and their real-life implementations.

# Integration

# Use as a standalone plugin

The track changes feature does not require real-time collaboration to work. If you prefer a more traditional approach to document editing, track changes can be added to CKEditor 5 just like any other plugin.

To learn how to integrate track changes as a standalone plugin, please refer to the Integrating track changes with your application guide.

# Use with real-time collaboration

If you are using the real-time collaboration feature, refer to the Real-time collaboration features integration guide.

# Learn more

After you run the track changes feature in your editor, you may want to learn more about it. Find out below how it works, how it can be configured, customized, and extended, to fit your application the best way possible.

# Configuration

The configuration for the track changes feature can be found in the TrackChangesConfig API reference.

# Suggestions markup

Suggestions are always attached to some place in the document. To make sure that they will not be lost, the track changes plugin adds some special markup to the document:

  • <suggestion-start> and <suggestion-end> tags are added if the suggestion starts/ends in text,
  • otherwise, the following attributes are added to elements:
    • data-suggestion-start-before,
    • data-suggestion-end-after,
    • data-suggestion-start-after,
    • data-suggestion-end-before.

Also, the <suggestion-td> tag is used for table cells pasting suggestions to separate old content (original) from the new content (pasted).

Read more about marker-to-data conversion to understand what data you may expect.

Examples of the possible markup:

Replacing the word “chocolate” with the word “ice-cream”:

<p>
    I like
    <suggestion-start name="insertion:e8ghd7:e390dk"></suggestion-start>ice-cream<suggestion-end name="insertion:e8ghd7:e390dk"></suggestion-end>
    <suggestion-start name="deletion:ejd853:e390dk"></suggestion-start>chocolate<suggestion-end name="deletion:ejd853:e390dk"></suggestion-end>.
</p>

Inserting image:

<figure class="image" data-suggestion-end-after="insertion:e1f0810:eohfu9" data-suggestion-start-before="insertion:e1f0810:eohfu9">
    <img src="foo.jpg">
    <figcaption>Image caption.</figcaption>
</figure>

Adding bold:

<p>
    This is
    <suggestion-start name="attribute:bold|ci1tcnk0lkep:ekeij:e3404"></suggestion-start>
    <strong>important</strong>
    <suggestion-end name="attribute:bold|ci1tcnk0lkep:ekeij:e3404"></suggestion-end>
    .
</p>

Pasting a table cell with the text “New” into a table cell with the text “Old”:

<td ...>
    <suggestion-td data-suggestion-end-after="insertion:..." data-suggestion-start-before="insertion:...">
        <p>New</p>
    </suggestion-td>
    <suggestion-td data-suggestion-end-after="deletion:..." data-suggestion-start-before="deletion:...">
        <p>Old</p>
    </suggestion-td>
</td>

Note that if your application filters HTML content, for example, to prevent XSS, make sure to leave the suggestion tags and attributes in place when saving the content in the database. The suggestion markup is necessary for further editing sessions.

# Suggestions attributes

Suggestion attributes is additional data stored with the suggestions and used by other features. You can also use them to set and read custom data necessary by your custom features built around suggestions.

suggestion.setAttribute( 'isImportant', true );

You can group multiple values in an object, using dot notation:

suggestion.setAttribute( 'customData.type', 'image' );
suggestion.setAttribute( 'customData.src', 'foo.jpg' );

Attributes set on the suggestion can be accessed through attribute property:

const isImportant = suggestion.attributes.isImportant;
const type = suggestion.attributes.customData.type;

You can also observe attributes property or bind other properties to it:

myObj.bind( 'customData' ).to( suggestion, 'attributes', attributes => attributes.customData );

Whenever setAttribute() or removeAttribute() is called, the attributes property is re-set, and observables are refreshed. Using these fires the update method in an adapter.

# Saving the data without suggestions

If you need to get the editor data with all the existing suggestions accepted or discarded, please refer to the dedicated guide.

# Saving the data with suggestion highlights

By default, the data returned by editor.getData() contains the markup for the suggestions as described above. It does not provide the markup that visually shows the suggestion highlights in the data (similarly to how they are shown in the editor).

It is possible to change the editor output using the showSuggestionHighlights option passed in editor.getData(). When set, the editor output will return suggestions similarly to how they are present inside the editor:

editor.getData( { showSuggestionHighlights: true } );

Will return:

<p>
    <span class="ck-suggestion-marker ck-suggestion-marker-formatInline">
        Foo
    </span>
    bar
</p>

The output data generated using the showSuggestionHighlights option cannot be used to load the editor data (it cannot be passed to editor.setData())!

This feature should be used for preview purposes and can be used, for example, together with the export to PDF feature.

The export to PDF feature can be integrated with the suggestion highlights as shown below:

{
    exportPdf: {
        // More configuration of the Export to PDF.
 		// ...
        dataCallback: editor => editor.getData( {
            showSuggestionHighlights: true
        } )
    }
}

# Force track changes mode to be enabled

If you would like to have track changes enabled by default, execute the trackChanges command, which toggles the track changes mode. It should be done after the editor instance is initialized:

ClassicEditor
    .create( document.querySelector( '#editor' ), {
       // Editor's configuartion.
 		// ...
    } )
    .then( editor => {
        editor.execute( 'trackChanges' );
    } )
    .catch( error => console.error( error ) );

You can disable the trackChanges command to prevent turning the track changes on or off. This can be useful for example when a particular user has permissions only to create suggestions in a given document. You can disable the command by calling Command#forceDisabled():

ClassicEditor
        .create( document.querySelector( '#editor' ), {
            // Editor's configuartion.
 			// ...
        } )
        .then( editor => {
            editor.execute( 'trackChanges' );

            editor.commands.get( 'trackChanges' ).forceDisabled( 'suggestionsMode' );
        } )
        .catch( error => console.error( error ) );

To prevent a user from accepting or discarding suggestions, disable commands responsible for these actions:

ClassicEditor
        .create( document.querySelector( '#editor' ), {
            // Editor's configuartion.
 			// ...
        } )
        .then( editor => {
          editor.execute( 'trackChanges' );

          editor.commands.get( 'trackChanges' ).forceDisabled( 'suggestionsMode' );
          editor.commands.get( 'acceptSuggestion' ).forceDisabled( 'suggestionsMode' );
          editor.commands.get( 'acceptAllSuggestions' ).forceDisabled( 'suggestionsMode' );
          editor.commands.get( 'discardAllSuggestions' ).forceDisabled( 'suggestionsMode' );
          editor.commands.get( 'discardSuggestion' ).forceDisabled( 'suggestionsMode' );
        } )
        .catch( error => console.error( error ) );

Keep in mind that the 'suggestionsMode' identifier can be later used to enable commands using Command#clearForceDisabled().

# Markers styling

Similarly to everywhere in the CKEditor 5 Ecosystem, we have used CSS Variables to let the developers customize the design of such UI elements as, for example, suggestion markers. You can override these properties with a .css file or place your customizations directly into the <head> section of your page, but in this case, you will need to use a more specific CSS selector than :root (like <body>).

Check out the color sheet for the full list of customizable colors. You can also browse other files with CSS Variables in CKEditor 5.

Here you can find the default CSS Variables used for the track changes feature:

:root {
    /* You can override the design of suggestion markers in the content. */

    /* Variables responsible for suggestions for text: */
    --ck-color-suggestion-marker-insertion-border: hsla(128, 71%, 40%, .35);
    --ck-color-suggestion-marker-insertion-border-active: hsla(128, 71%, 25%, .5);
    --ck-color-suggestion-marker-insertion-background: hsla(128, 71%, 65%, .35);
    --ck-color-suggestion-marker-insertion-background-active: hsla(128, 71%, 50%, .5);

    --ck-color-suggestion-marker-deletion-border: hsla(345, 71%, 40%, .35);
    --ck-color-suggestion-marker-deletion-border-active: hsla(345, 71%, 25%, .5);
    --ck-color-suggestion-marker-deletion-background: hsla(345, 71%, 65%, .35);
    --ck-color-suggestion-marker-deletion-background-active: hsla(345, 71%, 50%, .5);
    --ck-color-suggestion-marker-deletion-stroke: hsla(345, 71%, 20%, .5);

    --ck-color-suggestion-marker-format-border: hsla(191, 90%, 40%, .4);
    --ck-color-suggestion-marker-format-border-active: hsla(191, 90%, 40%, .65);

    /* Variables responsible for the left border of the suggestion boxes in the sidebar: */
    --ck-color-comment-box-border: hsl(55, 98%, 48%);
    --ck-color-suggestion-box-deletion-border: hsl(345, 62%, 60%);
    --ck-color-suggestion-box-insertion-border: hsl(128, 62%, 60%);
    --ck-color-suggestion-box-format-border: hsl(191, 62%, 60%);

    /* Variables responsible for the styling of suggestions for widgets: */
    --ck-color-suggestion-widget-insertion-background: hsla(128, 71%, 65%, .05);
    --ck-color-suggestion-widget-insertion-background-active: hsla(128, 71%, 50%, .07);
    --ck-color-suggestion-widget-deletion-background: hsla(345, 71%, 65%, .05);
    --ck-color-suggestion-widget-deletion-background-active: hsla(345, 71%, 45%, .07);
    --ck-color-suggestion-widget-format-background: hsla(191, 90%, 40%, .09);
    --ck-color-suggestion-widget-format-background-active: hsla(191, 90%, 40%, .16);

    --ck-color-suggestion-widget-th-insertion-background: hsla(128, 71%, 65%, .1);
    --ck-color-suggestion-widget-th-insertion-background-active: hsla(128, 71%, 50%, .12);
    --ck-color-suggestion-widget-th-deletion-background: hsla(345, 71%, 65%, .1);
    --ck-color-suggestion-widget-th-deletion-background-active: hsla(345, 71%, 45%, .12);
}

# API overview

Check the track changes API documentation for detailed information about the track changes API. Making yourself familiar with the API may help you understand the code snippets.

# Suggestions annotations customization

The suggestions annotations are highly customizable. Please refer to the Annotation customization guide to learn more.

# Integration with custom features

If you provide your own plugins, you may want to integrate these custom features with track changes mode.