Inline CSS plugin

This plugin is only available for paid TinyMCE subscriptions.
This feature is only available for TinyMCE 6.3 and later.

As is normal and long-time best practice, TinyMCE documents keep CSS and HTML separate. This practice is not, however, email-friendly.

The Inline CSS plugin takes a TinyMCE document, and processes it such that the previously separate CSS is applied inline to each HTML element. This single output file is much closer to the common requirements for sending as an HTML-formatted email.

Interactive example

  • TinyMCE

  • HTML

  • JS

  • Edit on CodePen

Click the button to export content with CSS inlined



Raw HTML output



Rendered output

<textarea id="inline-css" class="classic">
  <h1>TinyMCE documents and Inline CSS documents</h1>

  <h2>TinyMCE documents</h2>

  <p><em>TinyMCE</em> documents consist of</p>

  <ul>
  <li>material marked up as HTML;</li>
  <li>stylesheets defined by the <code>content_css</code> and <code>font_css</code> options; and</li>
  <li>CSS defined by the <code>style_css</code> option.</li>
  </ul>

  <h2>Inline CSS</h2>

  By contrast, <em>Inline CSS</em> documents consist of

  <ul>
  <li>a single file with all CSS styling applied inline to each HTML element.</li>
  </ul>

  <h2>The TinyMCE Inline CSS plugin</h2>

  <p>The TinyMCE Inline CSS plugin takes a TinyMCE document, with its multiple components.</p>

  <p>And returns a single file, with all CSS styling applied inline to each HTML element.</p>

  <p>As an example, below is a small text section with various styles applied. Press the <strong>Inline CSS</strong> button to view the content where all CSS are inlined</p>
  <br>
  <p class="red">Red text</p>
  <p class="red blue-background">Red text - blue background</p>
  <p class="blue">Blue text</p>
  <p class="blue red-background">Blue text - red background</p>

</textarea>

<div id="inlinecss-api-runner">
  <h1> Click the button to export content with CSS inlined</h1>
  <button id="inline-css-btn" style="margin: 10px">Inline CSS</button>
  <br/>
  <br/>

  <h2>Raw HTML output</h2>
  <textarea style="display: block; min-height: 250px; width: 100%;" id='output-text-area'></textarea>
  <br/>
  <br/>

  <h2>Rendered output </h2>
  <div style="height: 400px; display: flex; flex-direction: column; overflow: hidden;">
    <iframe style="flex: 1; height: 100%; width: 100%" id="outputIframe"></iframe>
  </div>
</div>
const settings = {
  plugins: [
    'advlist', 'anchor', 'autolink', 'charmap', 'code', 'fullscreen',
    'help', 'image', 'insertdatetime', 'link', 'lists', 'media',
    'preview', 'searchreplace', 'table', 'visualblocks', 'inlinecss'
  ],
  toolbar: 'undo redo | styles | bold italic underline strikethrough | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image',
  content_style: `
    .red {
      color: red;
    }
    .blue {
      color: blue;
    }
    .blue-background {
      background-color: blue;
    }
    .red-background {
      background-color: red;
    }
  `
};

tinymce.init({
  selector: 'textarea.classic',
  ...settings
});

const button = document.getElementById('inline-css-btn');
const outputTextArea = document.getElementById('output-text-area');

button.addEventListener('click', () => {
  const pluginAPI = tinymce.get(0).plugins.inlinecss;
  const outputIframe = document.getElementById('outputIframe');
  const rawDoc = outputIframe.contentWindow.document;
  pluginAPI.getContent().then((content) => {
    outputTextArea.value = content.html;

    if (rawDoc) {
      rawDoc.open();
      rawDoc.write(content.html);
      rawDoc.close();
    }
  });
});

Basic setup

To add the Inline CSS plugin to the editor, add inlinecss to the plugins option in the editor configuration.

For example:

tinymce.init({
  selector: 'textarea',  // change this value according to your HTML
  plugins: 'inlinecss',
});

Usage notes

The Inline CSS plugin does not support

  1. Pseudo-classes (for example button:hover { color: blue; }).

  2. Pseudo-elements (for example p::first-line { color: blue; })

  3. @ rules (for example @media (screen))

  4. The !important property.

Iframe mode is fully supported with some notable limitations

Since iframe is a sandbox, specifying CSS is reasonably constrained at this stage.

CSS styling information can be specified in several places for iframe mode:

  • A CSS stylesheet that is specified in the <head> of the iframe document i.e. <link rel="stylesheet" href="styles.css">

    • The supported way to add a stylesheet in TinyMCE is using the content_css option which automatically creates the <link> tag and puts it in the <head> of the document.

    • The user can also manually insert a stylesheet link in the <head> of the iframe.

  • A <style> tag in the <head> of the iframe document i.e. <style>p { color: red; }</style>

    • The supported way to add a style tag in TinyMCE, is using the content_style option which automatically creates the <style> tag and puts in the head of the document

    • The user can manually insert a style tag in the <head> of the iframe.

  • A style attribute on an element within the content i.e. inline CSS

It is worth noting that by default, TinyMCE does not support having a <style> tags as part of the body HTML content.

Inline mode is supported with some notable limitations

As inline mode for TinyMCE editor is not sandboxed and as a result, any CSS specified on the main page can have an effect on how the editor content looks.

CSS styling information can be specified in several places for inline mode:

  • A CSS stylesheet that is specified in the <head> of the page i.e. <link rel="stylesheet" href="styles.css">

    • Adding a stylesheet in TinyMCE, can be done by using the content_css option which automatically creates the <link> tag in the <head> of the page.

      • It is recommended to not use the content_css option though and just manually include the stylesheets.

      • The user can also manually insert a stylesheet link in the <head> of the page.

  • A CSS stylesheet that is specified in the <body> of the page i.e. <link rel="stylesheet" href="styles.css">

    • This is not recommended by MDN, but some browsers do allow it

  • A <style> in the <head> of the page i.e. <style>p { color: red; }</style>

    • To add a <style> in TinyMCE is by using the content_style option which automatically creates the <style> tag in the <head> of the document

    • The user can also manually put a <style> tag in the <head> of the page.

  • A <style> in the <body> of the page

    • As noted in the Classic iframe section, this should not be done, but some browsers will still allow it.

  • A style attribute on an TinyMCE element within the content i.e. inline CSS

Shadow DOM is supported but not officially, with some notable limitations

Shadow DOM is not officially supported by TinyMCE, but the feature will work when an editor running in inline or iframe is contained within a shadow root.

When an iframe mode editor is contained with a shadow root, the editor content can be styled the same way, where the expected behavior for the feature is that it should not have to consider if the editor is in a shadow root. When an inline editor is contained within a shadow root, the stylesheet (<link> tags) and <style> tags are added directly as children of the shadow root and do not need to be contained within a <head> tag.

When in inline mode, the feature checks if the editor is inside a shadow root to ensure it does not try to get <styles> that are outside the shadow root.

When an editor is in a shadow root, the feature should still support getting the stylesheets specified via the content_css option as well as the CSS styles specified via the`content_style` option.

Options

The following configuration options affect the behavior of the Inline CSS plugin.

inline_selector_filter

Determines whether it is valid for a given CSS selector to have its CSS properties inlined into the HTML content

Default: All selectors are considered valid to have their CSS inlined

Type: String RegExp or Function

inlinecss_selector_filter: (selector: string): boolean => {
  return selector.indexOf('myprefix') !== -1;
}

inline_file_filter

Determines whether it is valid for a given CSS stylesheet to have its CSS inspected and inlined into the HTML content

Default: All CSS stylesheet are considered valid to have their CSS inspected and inlined

Type: String RegExp or Function

inlinecss_file_filter: (href: string): boolean => {
  return selector.indexOf('mystyles') !== -1;
}

Events

The Inline CSS plugin provides the following events.

The following events are provided by the Inline CSS plugin.

Name Data Description

InlineCSS

N/A

Fired when inlining the CSS begins.

APIs

The Inline CSS plugin provides the following APIs.

A new API, editor.plugins.inlinecss.getContent(); has been added to support the new InlineCSS plugin

The API’s function is to take a TinyMCE document, and processes it such that the previously separate CSS is applied inline to each HTML element. The editor.plugins.inlinecss.getContent(); API does not require configuration from the user

The API will do the following

  • Fire the 'InlineCSS' event

  • Get the editor’s content by calling the editor.plugins.inlinecss.getContent();

  • Collect all of the stylesheets defined by the content_css option

  • Collect all styles specified in the content_style option

  • Combine content_css and content_style styles while making sure content_style has a higher precedent

  • Iterate over the content within the TinyMCE editor viewport, by inlining any InlineCSS styles where it finds a selector match

  • Return an object that contains the content with InlineCSS as a string

Example

interface PluginAPI {
  getContent: () => Promise<{
    html: string;
  }>
}

Result output after the InlineCSS content has been applied by the API

{
  html: '<p style="color: red;">hello</p>'
}