Export with inline styles

The export with inline styles feature applies the styles defined by CSS style sheets directly on HTML elements. For example, a global <p class="red"> style defining the font color to be red, will be turned into <p style="color: red">. This is especially useful for email creation but may be helpful in other use cases.

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

Use the Source editing command Source editing to see changes. Check the output below to see the exported content with inline styles applied.

Switch the tabs below to see three different outputs: the HTML tags with classes, CSS styles, and the HTML with those styles inlined. The last output shows how the exported content would look like.

The preview below shows the rendered content with inlined styles.

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

# 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.

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

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

ClassicEditor
	.create( document.querySelector( '#editor' ), {
		licenseKey: '<YOUR_LICENSE_KEY>',
		plugins: [ ExportInlineStyles, /* ... */ ],
		exportInlineStyles: {
			// Configuration.
		}
	} )
	.then( editor => {
		editor.execute( 'exportInlineStyles' )
			.then( html => {
				console.log( 'Email-ready content with proper HTML attributes:', html );
			} );
		// ...
	} )
	.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

The export with inline styles feature can be configured using the exportInlineStyles configuration object:

ClassicEditor
    .create( document.querySelector( '#editor' ), {
        // ... Other configuration options ...
        exportInlineStyles: {
            stylesheets: [ './path/to/custom-styles.css' ],
            inlineCss: `
                .ck-content {
                    .warning { color: red; }
                    .note { background: yellow; }
                }
            `,
            stripCssClasses: true
            // ...
        }
    } )

# Stylesheets

An array with paths to CSS files to process. The order matters as later files can override styles from earlier ones. The distinct 'EDITOR_STYLES' token includes default editor content styles. The option defaults to [ 'EDITOR_STYLES' ].

ClassicEditor
    .create( document.querySelector( '#editor' ), {
        // ... Other configuration options ...
        exportInlineStyles: {
            stylesheets: [
                './path/to/base-styles.css',	// Processed first.
                './path/to/theme-styles.css',	// Can override base styles.
                './path/to/custom-styles.css'	// Has highest priority.
            ]
            // ...
        }
    } )

The 'EDITOR_STYLES' token is supported only in legacy custom builds with webpack or DLLs. In other setups, you need to provide style sheet paths explicitly.

⚠️ CSS selectors must include the .ck-content prefix

Styles without this prefix will be ignored during the inline styles transformation. You can use CSS nesting with .ck-content as the parent:

For example:

/* ❌ This style will be ignored */
.warning { color: red; }

/* ✅ This style will be processed - flat approach */
.ck-content .warning { color: red; }

/* ✅ This style will be processed - nested approach */
.ck-content {
	.warning { color: red; }
}

⚠️ Direct styles on .ck-content are inherited by first-level children

Any styles set directly on the .ck-content element will be copied to all its direct children during export. This is because the .ck-content element itself is synthetic and not part of the exported content.

For example, if you define styles like color: red and font-family: Arial on .ck-content, all first-level elements such as paragraphs and lists will have these styles directly applied to them in the exported content. This inheritance only applies to first-level children, not to deeper descendants.

# Inline CSS

A string containing CSS rules to apply after processing the external style sheets. Useful for adding supplemental styles without external files. The option defaults to an empty string.

ClassicEditor
    .create( document.querySelector( '#editor' ), {
        // ... Other configuration options ...
        exportInlineStyles: {
            inlineCss: `
                .ck-content {
                    /* Styles directly applied to .ck-content */
                    color: blue;
                    font-family: Arial;

                    /* Nested styles for children */
                    .warning {
                        color: red;
                        font-weight: bold;
                    }
                    .highlight {
                        background: yellow;
                    }
                }
            `
            // ...
        }
    } )

# Strip CSS classes

When set to true, the feature will remove the CSS classes from elements after inline styles are applied. This ensures the exported content preserves styling without depending on external style sheets. The option defaults to false.

ClassicEditor
    .create( document.querySelector( '#editor' ), {
        // ... Other configuration options ...
        exportInlineStyles: {
            stripCssClasses: true
            // ...
        }
    } )

# Transformations

An array of functions that allow you to modify the elements and their styles before applying inline styles. Each function receives the element and a stylesMap object, which contains the computed styles for that element. You can use this to add, remove, or modify styles based on your needs.

ClassicEditor
    .create( document.querySelector( '#editor' ), {
        // ... Other configuration options ...
        exportInlineStyles: {
            transformations: [
                ( element, stylesMap ) => {
                    // Example transformation: Add a custom attribute to all paragraphs.
                    if ( element.tagName === 'P' ) {
                        element.setAttribute( 'data-paragraph', 'true' );
                    }
                }
            ]
            // ...
        }
    } )

We also provide a handy transformation helper for email creation use cases. These transformations improve compatibility with email clients by converting modern CSS properties to better-supported HTML attributes.

import { ClassicEditor } from 'ckeditor5';
import { ExportInlineStyles, getEmailInlineStylesTransformations } from 'ckeditor5-premium-features';

ClassicEditor
	.create( document.querySelector( '#editor' ), {
		// ... Other configuration options ...
		exportInlineStyles: {
			// Add email-specific transformations to the editor configuration.
			transformations: getEmailInlineStylesTransformations()
			// ...
		}
	} )
	.then( editor => {
		// When exporting content, the email transformations will be applied automatically.
		editor.execute( 'exportInlineStyles' )
			.then( html => {
				console.log( 'Email-ready content with proper HTML attributes:', html );
			} );
	} )
	.catch( error => {
		console.error( error );
	} );

# Usage

To export the editor content with inline styles, use the ExportInlineStyles command:

editor.execute( 'exportInlineStyles' )
    .then( ( html ) => {
        console.log( html );
    } )
    .catch( ( error ) => {
        console.error( error );
    } );

You can also pass configuration options directly to the command. These options will override any editor configuration settings:

editor.execute( 'exportInlineStyles', {
    stylesheets: [ './path/to/custom-styles.css' ],
    inlineCss: '.ck-content .warning { color: red; }',
    stripCssClasses: true,
    transformations: [ /* custom transformations */ ]
} )
    .then( ( html ) => {
        console.log( html );
    } )
    .catch( ( error ) => {
        console.error( error );
    } );

The command outputs the exported content as an HTML string with inline styles applied. You can then use the content in email templates, CMS systems, or other environments where external CSS is not supported.

⚠️ One-way transformation

The exported content should not be loaded back to the editor. The content with inlined styles will render depending on the editor’s configuration and the UI of some features may not work correctly.

If you want to save the content with inlined styles, make sure to save the getData output as well as exportInlineStyles . Always load the editor with the getData output.

If you need to load content with inlined styles consider using the General HTML Support (“GHS”) feature. However, it may lose some of the original styling and document structure.

# Style transformations

The export with inline styles feature allows you to apply custom transformations to elements before inline styles are applied. Transformations enable you to modify elements and their styles programmatically during the export process.

# When transformations are invoked

Transformations are called for each element in the DOM tree during the export process:

  1. Child elements are processed first, before their parent elements.
  2. For each element, the transformation is executed immediately before inline styles are assigned to the element.

This execution order gives you powerful control over the exported content:

  • You can modify the element’s attributes and styles just before they are finalized.
  • You can add or remove styles from the stylesMap to customize the final appearance.
  • You can manipulate the element’s children (add, remove, or modify) since they are already processed when the parent’s transformation is called.
  • You can even remove elements completely from the output if needed.

# Example transformation

transformations: [
    ( element, stylesMap ) => {
        // Add a new style.
        if ( element.tagName === 'P' ) {
            stylesMap.set( 'line-height', '1.5' );
        }

        // Remove a style.
        if ( element.classList.contains( 'no-margin' ) ) {
            stylesMap.delete( 'margin' );
        }

        // Modify child structure.
        if ( element.classList.contains( 'box' ) ) {
            // Remove unwanted child elements.
            const unwantedElements = Array.from( element.querySelectorAll( '.remove-me' ) );
            unwantedElements.forEach( el => el.remove() );

            // Add new child element.
            const disclaimer = document.createElement( 'div' );
            disclaimer.textContent = 'Important notice';
            element.appendChild( disclaimer );
        }
    }
]

This processing approach provides flexibility for implementing complex export logic while ensuring all styles are properly applied to the modified DOM structure.

# Real-world example

Here is a simple example showing how to use this feature to export content for an email message:

// Button that exports the editor content for email use.
document.querySelector( '#export-for-email' ).addEventListener( 'click', () => {
    // Get content with inline styles with configuration options.
    editor.execute( 'exportInlineStyles', {
        // Specify which root to use (useful in multi-root editors).
        rootName: 'main',

        // Override editor configuration with email-specific settings.
        stylesheets: [ './email-styles.css' ],
        inlineCss: `
            .ck-content {
                font-family: Arial, sans-serif;
                .quote { font-style: italic; }
            }
        `,
        stripCssClasses: true,

        // Apply email-specific transformations.
        transformations: [
            ( element, stylesMap ) => {
                // Make all links color blue and underlined for better email client compatibility.
                if ( element.tagName === 'A' ) {
                    stylesMap.set( 'color', '#0066cc' );
                    stylesMap.set( 'text-decoration', 'underline' );
                }

                // Ensure all images have explicit width/height (helps with email rendering).
                if ( element.tagName === 'IMG' && !element.getAttribute( 'width' ) ) {
                    element.setAttribute( 'width', '300px' );
                    element.setAttribute( 'height', '100px' );
                }

                // Ensure paragraphs have margin for email spacing.
                if ( element.tagName === 'P' ) {
                    stylesMap.set( 'margin-bottom', '16px' );
                }
            }
        ],

        // Remove all classes to prevent dependency on external CSS.
        stripCssClasses: true
    } )
        .then( htmlWithInlineStyles => {
            // Use the exported content in your email sending logic.
            sendEmail( {
                subject: 'Newsletter',
                content: htmlWithInlineStyles,
                recipients: [ 'user@example.com' ]
            } );
        } )
        .catch( error => {
            console.error( 'Failed to export content:', error );
        } );
} );

// Example email sending function (would be replaced with your actual email API).
function sendEmail( emailData ) {
    console.log( 'Sending email with inline-styled content:', emailData );
    // Your email API call would go here:
    // emailAPI.send( emailData );
}

# Compatibility

# Supported features

  • Basic CSS properties (color, background-color, font-family, etc.)
  • Compound properties (background, margin, padding, etc.)
  • CSS variables (resolved during export)
  • Simple CSS selectors (class, id, element)

Supported pseudo-classes:

  • Structural pseudo-classes:
    • :first-child
    • :last-child
    • :nth-child()
    • :only-child
    • :empty
    • :nth-of-type()
    • :first-of-type
    • :last-of-type
  • Logical pseudo-classes:
    • :matches()
    • :not()
    • :is()
  • Root pseudo-class:
    • :root

# Limited or unsupported features

  • media queries
  • @import and @font-face rules
  • @keyframes and animation properties
  • transition properties
  • :before and :after pseudo-elements
  • Interactive state pseudo-classes:
    • :focus
    • :visited
    • :link
    • :hover
    • :active
  • Shadow DOM and ::part() selectors

Here are some other CKEditor 5 features that work well with the export with inline styles feature:

  • Email configuration helper – Ensure email-compatible content structure and validate against email client restrictions.
  • General HTML support – Add support for additional HTML elements and attributes in your content.
  • Style – Apply predefined styles to content elements that can be exported as inline styles.
  • Layout tables – Layout tables are used to structure a web page content spatially rather than for presenting tabular data.

# Common API

The ExportInlineStyles plugin registers the ExportInlineStyles command.

It accepts the optional rootName configuration parameter, which determines the editor root to use for content origin.

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.