#17374·mautic

GrapesJS email builder HTML-escapes CSS in <mj-style>, breaking child selectors on save and reopen

Author: patrykgruszkaCreated Sep 14, 2026Updated Sep 14, 2026

Mautic Series

7.1.x series

Mautic installed version

7.2.0

Way of installing

I cloned the Mautic repo (not recommended or supported)

PHP version

8.5.8

What browsers are you seeing the problem on?

Not relevant

What happened?

Saving an email in the GrapesJS builder corrupts CSS child selectors inside <mj-style>. editor.getHtml() escapes the contents, so:

css
.wrapper > table { max-width: 700px !important; }

becomes:

css
.wrapper &gt; table { max-width: 700px !important; }

That CSS is invalid. On reopen, the builder's PostCSS parser throws CssSyntaxError: Unknown word and rendering fails. The theme loads fine before the first save, so saving is what breaks the email.

Expected: raw CSS inside <mj-style> survives export, save, and reopen.

Root cause

GrapesJS core escapes every text node except those inside <script>. In grapesjs 0.22.16, ComponentTextNode.toHTML():

javascript
return parent?.is('script') ? content : this.__escapeContent(content);

escapeNodeContent() then applies .replace(/>/g, '&gt;'). grapesjs-mjml registers mj-style with no custom toHTML, so its CSS is treated as an ordinary text node. GrapesJS 0.22.16 has no style exemption anywhere.

Known upstream: https://github.com/GrapesJS/grapesjs/issues/3441 , reported 2021, closed without a core fix.

How can we reproduce this issue?

Step 1: Open an email theme with a CSS child selector (>) inside <mj-style> in the builder. It renders correctly. Step 2: Make any change and save. Step 3: Reopen the email. Rendering fails; the browser console reports the CSS parsing error.

Saved MJML shows > stored as &gt; inside <mj-style>.

Relevant log output

bash
CssSyntaxError: <css input>: Unknown word

Code of Conduct

  • I confirm that I have read and agree to follow this project's Code of Conduct



Care about this issue? Want to get it resolved sooner? If you are a member of Mautic, you can add some funds to the Bounties Project so that the person who completes this task can claim those funds once it is merged by a member of the core team! Read the docs here.