Report an issue

Preview final content

The content you work on may become heavily edited, including lots of suggestions, possibly coming from different authors. At some point, it may become difficult to understand what the final content will look like, after all suggestions are accepted. When this happens, you may use the track changes preview feature. When used, it will display a modal window with a preview of the content with all the suggestions accepted.

# Demo

Use the “Preview final content” button in the track changes toolbar dropdown Track changes (you can find it in the menu bar, in “Tools -> Track changes” menu). The editor will display a modal window with the preview. Add more suggestions to the document to see how the final content changes.

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

# Installation

To enable the track changes preview feature, add the TrackChangesPreview plugin to your editor setup:

import { ClassicEditor } from 'ckeditor5';
import { TrackChangesPreview } from 'ckeditor5-premium-features';

ClassicEditor
	.create( document.querySelector( '#editor' ), {
		licenseKey: '<YOUR_LICENSE_KEY>',
		plugins: [ TrackChangesPreview, /* ... */ ]
	} )
	.then( /* ... */ )
	.catch( /* ... */ );

The plugin will add a new “Preview final content” button to the track changes toolbar dropdown and in the “Tools -> Track changes” menu in the menu bar.

You can also execute previewFinalContent command to show the modal window with the preview:

editor.commands.get( 'previewFinalContent' ).execute();

# Configuration

When the preview is opened, the editor content is put inside a container element, which has the same CSS classes as the editor’s editable element. In most cases this is sufficient to replicate the styling of editor content.

If you see that your custom CSS styles are not applied in the preview, make sure that your CSS rules also apply to the HTML in the preview modal. You may need to adjust selectors in your CSS rules to match the preview dialog structure.

By default, the editor content is put into a following DOM structure:

<div class="ck ck-track-changes-preview" ...>
    <div class="ck ck-content ck-editor__editable ck-track-changes-preview__root-container ..." data-ck-root-name="main">
        <!-- Editor content goes here. !-->
    </div>
</div>

You can target the ck-track-changes-preview and ck-track-changes-preview__root-container classes, as well as data-ck-root-name attribute.

However, some integrations may require a custom DOM structure, for example due to complex CSS rules, or if you use MultiRootEditor. To provide a custom DOM structure inside the preview modal dialog, use the trackChanges.preview.renderFunction configuration option.

{
    trackChanges: {
        preview: {
            renderFunction: ( container, elements ) => {
                // Custom callback inserting the `elements` into `container`.
                // ...
            }
        }
    }
}

Two parameters are passed to the callback:

  • container – the main container element that will be inserted into the modal window (this is the element with the ck-track-changes-preview CSS class).
  • elements – an array of elements, each holding the contents of one of the editor roots. Unless you are using MultiRootEditor, there will be only one element available. They are sorted according to their DOM order. Each element has the data-ck-root-name attribute set to the corresponding editor’s root name. You can use them for styling purposes, or to recognize a particular root and handle it in some custom way.

Use renderFunction to process the elements array, wrap them in a DOM structure that will fit your needs, and insert them into container element.

Below is an example of how renderFunction could be used together with a multi-root editor:

ClassicEditor
    .create( document.querySelector( '#editor' ), {
        // ... Other configuration options ...
        trackChanges: {
            preview: {
                renderFunction: ( container, elements ) => {
                    for ( const element of elements ) {
                        // Wrap each root into an additional container.
                        const dataContainer = document.createElement( 'div' );

                        dataContainer.classList.add( 'additional-container' );
                        dataContainer.appendChild( element );

                        container.appendChild( dataContainer );
                    }
                }
            }
        }
    } )
    .then( /* ... */ )
    .catch( /* ... */ );

This will result in the following structure inside the preview modal window:

<div class="ck ck-track-changes-preview" ...>
    <div class="additional-container">
        <div class="ck ck-content ck-editor__editable ck-track-changes-preview__root-container ..." data-ck-root-name="root-a">
            <!-- Editor content for "root-a" goes here. !-->
        </div>
    </div>
    <div class="additional-container">
        <div class="ck ck-content ck-editor__editable ck-track-changes-preview__root-container ..." data-ck-root-name="root-b">
            <!-- Editor content for "root-b" goes here. !-->
        </div>
    </div>
    <div class="additional-container">
        <div class="ck ck-content ck-editor__editable ck-track-changes-preview__root-container ..." data-ck-root-name="root-c">
            <!-- Editor content for "root-c" goes here. !-->
        </div>
    </div>
</div>