Merge fields

Merge fields are visually distinct placeholder elements, which you may put into the content to mark places, where real values should be inserted. This is perfect for creating document templates and other kinds of personalized content.

The feature is highly customizable, offers text and block placeholders, a preview mode, and is integrated with our document export and import plugins.

Below we present the typical use cases for the feature. Choose the setup that fits your needs the best.

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.

# Template editing

The most popular use case is creating templates of documents, e-mails, invoices, and other kinds of personalized content.

Dear {{guestTitle}} {{guestName}}

This email confirms your reservation at Serenity Springs Resort for a relaxing {{roomType}} experience. We're delighted to welcome you on {{guestArrivalDate}}!

{{additionalValueProposition}}

Sincerely
The Team at Serenity Springs Resort

The user can insert one of the pre-configured merge field elements in various ways:

  • from a toolbar dropdown ,
  • from the menu bar, under “Insert” → “Merge field”,
  • or by typing the opening bracket ({{ by default), and choosing one of the merge fields from the list.

To enable this use case, simply configure the merge fields definitions and add a button to the toolbar.

You can learn more about configuring the feature in the Configuration section of this guide.

Presented demos show a limited set of features. Visit the feature-rich editor example to see more in action.

# Preview mode

Enhance the template creation experience by defining example preview data sets.

As the user prepares the template, they will be able to switch to a data preview mode. In this mode, merge fields labels are replaced with values taken from the chosen data set. This way, the user will have a better understanding how the actual, final content may look like.

Dear {{guestTitle}} {{guestName}}

This email confirms your reservation at Serenity Springs Resort for a relaxing {{roomType}} experience. We're delighted to welcome you on {{guestArrivalDate}}!

{{additionalValueProposition}}

Sincerely
The Team at Serenity Springs Resort

The default initial preview mode is “labels”. When the data for other preview modes is provided, the preview modes can be switched using a toolbar dropdown , or through the menu bar (“View” → “Merge fields preview”).

# Data-only setup

Instead of showing the labels, the editor can be configured to always display the merge fields values, without a way to switch it. The user will insert the merge fields into the content as previously, but they will always see the defined data.

This setup is perfect when you want to use a previously prepared template to create a concrete piece of content, in the context of a specific data set (e.g. customer data), possibly editing it along the way to further personalize the content.

Using merge fields in this configuration is useful even when you start from scratch! The user avoids typos and has convenient access to correct values, while the created document is always up-to-date, in case the related data set changes.

Dear {{guestTitle}} {{guestName}}

This email confirms your reservation at Serenity Springs Resort for a relaxing {{roomType}} experience. We're delighted to welcome you on {{guestArrivalDate}}!

{{additionalValueProposition}}

Sincerely
The Team at Serenity Springs Resort

To enable this use case, use feature configuration to provide a data set, set the initial preview mode and disable other preview modes.

Apart from providing data sets, you can also define default values for the merge fields. The default value is used when the data set is missing a value for a given merge field. Additionally, an error indicator is displayed, to make the user aware of a possible problem. This is useful when you cannot guarantee that your data sets are always complete.

# Installation

⚠️ New import paths

Starting with version 42.0.0, we changed the format of import paths. This guide uses the new, shorter format. Refer to the Packages in the legacy setup guide if you use an older version of CKEditor 5.

The merge fields feature uses the mentions feature under the hood, so ensure you install it too.

After installing the editor, add the feature to your plugin list and toolbar configuration:

import { ClassicEditor, Mention } from 'ckeditor5';
import { MergeFields } from 'ckeditor5-premium-features';

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

# Activating the feature

To use this premium feature, you need to activate it with proper credentials. Refer to the License key and activation guide for details.

# Configuration

For more technical details, check the plugin configuration reference.

To make the most out of the merge fields feature, it has to be properly configured. Some options (such as prefix and suffix or preview modes) have a reasonable default set, but it is essential to at least define the list of the available merge fields.

# Merge fields definitions

To make the merge fields appear in the editor UI you have to specify them in the mergeFields.definitions property.

ClassicEditor
    .create( document.querySelector( '#editor' ), {
        // ... Other configuration options ...
        mergeFields: {
            definitions: [
                {
                    id: 'guestName',
                    label: 'Guest name', // Optional.
                    defaultValue: 'Guest' // Optional.
                },
                {
                    id: 'guestSpecialOffersBox',
                    label: 'Special offers', // Optional.
                    type: 'block', // Optional.
                    height: '150' // Optional.
                },
                // More merge field definitions.
            ]
        }
    } )
    .then( /* ... */ )
    .catch( /* ... */ );

The merge field id is the only required value, and it is used in the document data returned by the editor. It may include letters, numbers and _, ., - special characters.

The merge field label is displayed in the editor, if defined. If not, the id is used instead.

Custom (non-defined) merge fields may be inserted into the document as well.

Use “Source editing” feature in the presented demos to see an example of the editor output.

# Merge field type

The feature supports two different types of merge fields:

  1. Typical, inline, text merge fields, most often replaced by textual data. For example, a customer name or invoice number.
  2. Block merge fields, which represent a bigger piece of content, replaced by an arbitrary HTML structure. For example, a row with box presenting top selling products or an email footer.

You can define the merge field type using type property. Possible values are: 'text' (default) and 'block'.

ClassicEditor
    .create( document.querySelector( '#editor' ), {
        mergeFields: {
            definitions: [
                {
                    id: 'guestAddress',
                    type: 'block',
                    label: 'Guest address' // Optional.
                },
                // More merge field definitions.
            ]
        }
    } )
    .then( /* ... */ )
    .catch( /* ... */ );

In the editor, text merge fields are treated like text. They can be placed only where text is allowed, can be formatted, or be a link. Block merge fields behave like other block-level widgets, and can be placed only where blocks are allowed.

For block merge fields, it is possible to configure how much vertical space should they occupy. This makes it easier to better visualize how the actual content will look like, or predict the page breaks. Set it using the height property (150px by default). Note, that this setting is used only if data for given merge field is not displayed. In a preview mode, the merge field height will depend on the merge field content.

ClassicEditor
    .create( document.querySelector( '#editor' ), {
        mergeFields: {
            definitions: [
                {
                    id: 'guestAddress',
                    type: 'block',
                    height: '100', // In pixels. Defaults to 150.
                    label: 'Guest address' // Optional.
                },
                // More merge field definitions.
            ]
        }
    } )
    .then( /* ... */ )
    .catch( /* ... */ );

When it comes to document data, the block merge fields are not wrapped in any HTML structure. It is assumed that the merge field will be replaced by some block-level HTML structure. See example document data below:

    <p>
        See the order details below.
    </p>
    {{orderDetails}}
    <p>
        <!-- Further content. -->
    </p>

# Grouping merge fields

To better organize the merge fields in the dropdown, you can divide the definitions into groups.

ClassicEditor
    .create( document.querySelector( '#editor' ), {
        // ... Other configuration options ...
        mergeFields: {
            definitions: [
                {
                    groupId: 'guest',
                    groupLabel: 'Guest',
                    definitions: [
                        {
                            id: 'guestName',
                            label: 'Guest name',
                            defaultValue: 'Guest'
                        },
                        {
                            id: 'guestTitle',
                            label: 'Guest title',
                            defaultValue: 'Ms./Mr.'
                        },
                        // More merge field definitions
                        // inside the "Guest" group.
                    ]
                },
                // More merge field groups.
            ]
        }
    } )
    .then( /* ... */ )
    .catch( /* ... */ );

# Prefix and suffix

The mergeFields.prefix and mergeFields.suffix (characters combinations used to indicate the start and end of the merge field) can be configured as well. The defined values will be returned in the editor uutput.

ClassicEditor
    .create( document.querySelector( '#editor' ), {
        // ... Other configuration options ...
        // Use different kind of brackets for merge fields indicators.
        mergeFields: {
            prefix: '[[',
            suffix: ']]'
        }
    } )
    .then( /* ... */ )
    .catch( /* ... */ );

The default merge fields brackets are {{ and }}. The following characters are allowed in prefix and suffix: '"`!#%:;=@{}~$()*+/?[\]^|. Additionally, they cannot be longer than 8 characters.

Note: The prefix and suffix must be different.

Note: The brackets that are used in the stored document data will not automatically update after you change the prefix or suffix configuration. The change will affect only the newly inserted merge fields. Additionally, old merge fields will not be recognized and will be displayed as plain text. If you need to change brackets configuration, you should also process the document data for all documents created in your application so far.

# Preview modes

The preview modes change how the merge fields are displayed in the editor area. The editor may display either merge fields labels (or ids), or data values, for preview purposes.

To be able to change preview modes, you will need to define either merge fields default values or data sets (described later on).

# Available preview modes

Use mergeFields.previewModes configuration option to specify which preview modes should be available for the user. It should be specified as any combination of the three possible values:

  • The “labels” view ('$labels' value) - displays labels (or ids, if not specified).
  • The “default values” view ('$defaultValues') - displays default values, if specified.
  • All the configured data sets ('$dataSets') - displays values for a chosen data set.
ClassicEditor
    .create( document.querySelector( '#editor' ), {
        // ... Other configuration options ...
        mergeFields: {
            // The user will be allowed only to switch between defined data sets,
            // and the merge fields will always display the data related to one of
            // the defined data sets. If there is only one data set, the user will
            // be forced to see the data from that set and will not be able to switch.
            previewModes: [ '$dataSets' ]
        }
    } )
    .then( /* ... */ )
    .catch( /* ... */ );

Note: At least one option must be defined.

Note: If only one preview mode is available (meaning, the passed value is [ '$labels' ], or [ '$defaultValues' ], or [ '$dataSets' ] with only one data set defined), the “Merge fields preview” button will not be added to the “View” menu.

# Initial preview mode

The mergeFields.initialPreviewMode option specifies which preview mode should be active when the editor is loaded. By default, merge field labels will be shown.

The passed value can be either of: '$labels', '$defaultValues', or one of the IDs of the defined data sets.

ClassicEditor
    .create( document.querySelector( '#editor' ), {
        // ... Other configuration options ...
        mergeFields: {
            // ID of a data set (see an example below).
            initialPreviewMode: '158673'
        }
    } )
    .then( /* ... */ )
    .catch( /* ... */ );

Note: The initial preview mode must be also specified as one of the available preview modes. Otherwise, an error will be thrown.

# Data sets

To be able to preview data in place of merge fields, you must define at least one data set. A data set should define values according to defined merge fields ids. If some values are not available, the merge fields default value will be used instead (if defined).

ClassicEditor
    .create( document.querySelector( '#editor' ), {
        // ... Other configuration options ...
        mergeFields: {
            dataSets: [
                {
                    id: '158673',
                    label: 'David Lee',
                    values: {
                        guestName: 'David Lee',
                        guestTitle: 'Mr.'
                        // Other values in this data set.
                    }
                },
                // More data sets.
            ]
        }
    } )
    .then( /* ... */ )
    .catch( /* ... */ );

# Using HTML tags in merge fields values

It is possible to use HTML code inside merge fields values, both in default values and the data set values.

By default, this behavior is disabled and merge fields values will be treated as plain text (HTML tags will get encoded). To enable HTML merge fields values:

It is strongly recommended to provide an HTML sanitization function.

If you enable HTML merge fields values, the HTML assigned to merge field will be rendered as-is when the user switches to the preview mode. As a result, the browser will execute any JavaScript code included in this HTML in the context of your website. This may lead to a security vulnerability, if the merge fields values are provided from an external source that cannot be fully trusted (e.g. users provide them in a different part of your application).

If you do not provide a sanitization function, a warning will be logged to the console.

You can provide your custom sanitization function or use one of the popular JavaScript libraries, like sanitize-html and DOMPurify.

The default settings of these libraries usually strip all potentially malicious content including <iframe>, <video>, or similar elements, as well as JavaScript code. You may need to adjust their settings to match your needs.

# Integration

# Editor data output

Merge fields are returned by editor.getData() as the merge field id enclosed in the specified prefix and suffix, for example: <p>Dear {{guestTitle}} {{guestName}}</p>. It is an industry standard format for representing merge fields, which makes it convenient to replace the merge fields with actual data.

Use “Source editing” feature in the presented demos to see an example of the editor output.

Note: Switching preview mode to display data set values does not affect the editor output. In most regular cases, you will always want to save the document data with the merge fields placeholders, not the values. The data replacement should happen in your application logic when needed.

# Data output with filled-in merge fields

In some cases, it may be useful to get the document data with the merge fields replaced by some actual data.

You may pass the values as an option to editor.getData() call:

const data = editor.getData( {
    mergeFieldsData: {
        guestName: 'Joe Doe',
        guestTitle: 'Mr.'
    }
} );

And the editor will use these values in place of given merge fields.

If data for a given merge field is not specified, the default data form will be used ([PREFIX][MERGE_FIELD_ID][SUFFIX], e.g. {{guestName}}).

Most likely, you will want to save the data with merge fields replaced by values from the currently previewed data set:

const mergeFieldsEditing = editor.plugins.get( 'MergeFieldsEditing' );

const mergeFieldsData = mergeFieldsEditing.getDataSetValues(
    mergeFieldsEditing.previewMode, true
);

const data = editor.getData( { mergeFieldsData } );

# Custom merge fields

The editor will convert every piece of text matching the merge field pattern to a merge field element. This behavior cannot be currently turned off.

Please note, that from the point of view of the editor output, it is indifferent whether the merge field matching text is recognized by the editor, as both defined and custom merge fields are represented the same in the editor output.

Custom merge fields can be added to the editor content by:

  • typing the merge field pattern, e.g. typing {{myMergeField}},
  • loading the document data with merge fields that were not specified in the merge fields definitions (including situations where previously existing merge field definition was later removed from the configuration),
  • pasting an external content that includes text matching the merge field pattern.

Custom merge field will behave like a merge field for which only an id was defined.

# Document export plugins

Using the export to Word or export to PDF features for a document with merge fields will produce different results, depending on the current preview mode. The export features will follow “what you see is what you export” logic.

While export is used in the “labels” preview mode:

  • The exported Word document will contain Word document merge fields (it will be exported as a “template” document).
  • The exported PDF file will contain merge fields in the default data form [PREFIX][MERGE_FIELD_ID][SUFFIX], e.g. {{guestName}}).

While export is used when default values or data set values are previewed, the merge fields will be replaced by corresponding values, as previewed in the editor area.

# Import from Word

Import from Word feature will recognize Word document merge fields and will seamlessly convert them to the editor merge fields.

# Using merge fields with templates

Merge fields can be used together with the template feature. Use the “Insert template” Insert template dropdown to add a template into the editor.

Dear {{guestTitle}} {{guestName}}

This email confirms your reservation at Serenity Springs Resort for a relaxing {{roomType}} experience. We're delighted to welcome you on {{guestArrivalDate}}!

Sincerely
The Team at Serenity Springs Resort
P.S. Mention this email to receive {{guestDiscount}} off your first spa treatment!

For more information about creating and using templates, visit the templates documentation.

# Common API

The MergeFields plugin registers:

If you have any further comments or suggestions about this feature, we will be happy if you contact us and share them!

We recommend using the official CKEditor 5 inspector for development and debugging. It will give you tons of useful information about the state of the editor such as internal data structures, selection, commands, and many more.