Missing inline styles used by CKEditor when adding raw html components
Question
GrapesJS version
- I confirm to use the latest version of GrapesJS
What browser are you using?
Chromium v96
Reproducible demo link
https://grapesjs.com/demo-newsletter-editor.html
Describe the bug
How to reproduce the bug?
- Open the developer tools at the console tab
- Run the code below
- Select the text added
- Edit something with CKEditor
- Select another component
What is the expected behavior? Expected to add inline styles from the spans inside the text component so that the CKEditor understand the text-styling and keep them when opened.
What is the current behavior?
Adding the raw HTML by editor.addComponent() do add the styling, but once you edit the text and blur it the style is removed from the text segments where they belong. This happens only with CKEditor because it uses the <span> and inline style to edit the text.
I'm putting the newsletter preset demo because it is the only demo from grapesjs that use CKEditor.
If is necessary to execute some code in order to reproduce the bug, paste it here below:
editor.DomComponents.clear()
editor.addComponents(`<div data-gjs-type="text"><span style="color: blue;">Teste</span> de <span style="font-family: arial; font-size: 25px"><b>span</b></span> inline</div>`)
I need to add components this way so that legacy HTML models and templates can be opened into grapesjs. Sometimes CKEditor even does not recognizes that spans or <b> elements are text segments and throw an error as it does not work with those text styling elements.
This problem is similar to #3069 that was fixed and I believe this has returned once the feature of transforming inline styles into classes was added.
Can we somehow keep the elements inside text components as raw html?
Code of Conduct
- I agree to follow this project's Code of Conduct
Answers (4)
+1
Hey I've been having similar issues. I think it's quite serious as both newsletter and mjml demo are affected. (Both use CKeditor as RTE)
When I import a content that has a text (mj-text) that has styled elements (span) the imported content gets parsed and the styling elements are recognized as individual components and not as contents of the wrapping text element.
example (This is valid according to mjml.io):
<mjml>
<mj-body>
<mj-section>
<mj-column>
<mj-image width="100px" src="/assets/img/logo-small.png"></mj-image>
<mj-divider border-color="#F45E43"></mj-divider>
<mj-text font-size="20px" font-family="helvetica"><strong>Hello</strong> <span style="color: #F45E43;">World</span></mj-text>
</mj-column>
</mj-section>
</mj-body>
</mjml>
Expected result:

Result:

The problem is that due to nested texts are parsed into components, their style attributes gets stripped and the result code does't contain it anymore:
<mjml>
<mj-body>
<mj-section>
<mj-column>
<mj-image width="100px" src="/assets/img/logo-small.png">
</mj-image>
<mj-divider border-color="#F45E43">
</mj-divider>
<mj-text font-size="20px" font-family="helvetica">
<strong>Hello</strong>
<span id="io1ak">World</span>
</mj-text>
</mj-column>
</mj-section>
</mj-body>
</mjml>
The style must be there under the hood somewhere. Because when I doubleclick on the text, the CKEditor loads and somehow "restores" the style attribute. But unless I open every text for editing on each content edit, the style gets lost.
Not all GrapesJS versions are affected.
0.21.1, and 0.21.1 are
But 0.16.3 - 0.19.5 behaves as expected.
I checked changes from 0.19.5 to 0.20.1 and I couldn't clearly trace back what could have casued the change in this behaviour. But probably has something to do with Support textable for extended Text components
Now I know that nested texts are native to grapesJS, since this is the default way of styling them. But is there a way to disable nested text feature?
ckeditor output:
<div>some rich text from <span style="color:blue">ckeditor</span></div>
after parsing into editor, become like:
<div data-gjs-type="text">some rich text from <span style="color:blue" data-gjs-type="default">ckeditor</span></div>
Basically every dom become components.
Maybe give a choice to developer to decide whether a component should stop add child nodes as components.
Can add a new flag property in component's model, eg: 'stopProcessChildren'
Inside ./parser/mode/ParserHtml.ts::parseNode() function,
right before going into the recurisve parseNode() and assigning child components
model.components = this.parseNode(node, {/*...*/});
- Add an else-if condition: if model's '
stopProcessChildren' is true, do not do the parseNode() on children nodes. - next, need to set the current dom node's innerHtml to model's '
content' or do this in component definition
From the default ./dom_components/model/Component.ts::toHTML() and ./dom_components/model/Component.ts::getInnerHTML(),
the html output should return model's 'content' if there are no child components.
Proposed component definition can be like:
editor.DomComponents.addType('my-rich-text', {
isComponent: el => {
if (allChildText(el)) { //check if all text node or tagname in textTags
return {
type: 'my-rich-text', // or can do 'text' here? not sure.
editable: true,
content: el.innerHtml,
components: false,
stopProcessChildren: true, //new property
};
}
},
// ...
});
Concerns: XXS
Thanks for reporting this, @gustavohleal.
Great suggestion about Missing inline styles used by CKEditor when adding raw html components! While this specific feature isn't yet in the core API, there are several ways to achieve similar behavior.
Using the event system:
editor.on('component:update', (component) => {
// your logic here
});
Alternative approaches:
- Listen to
selector:addfor CSS selector changes - Use
selector:customfor custom rules - Tap into the
change:*events for fine-grained tracking - Build a plugin that extends the editor with this capability
Making it official: If this feature would benefit many users, consider opening a formal Feature Request on the GrapesJS repo with:
- A detailed use case
- Code example showing the desired behavior
- Why this matters for your workflow
The core team is receptive to well-motivated feature requests backed by real use cases.
Related Questions and Answers
Continue research with similar issue discussions.
Issue #4225
BUG : The facebook plugin is not working in the grapes js
GrapesJS version[X] I confirm to use the latest version of GrapesJSWhat browser are you using? Chrome v9Reproducible demo link Not thereDes...
Issue #5156
Cannot drag drop in mobile screen even add grapejs-touch
GrapesJS version[X] I confirm to use the latest version of GrapesJSWhat browser are you using? Chrome, IOSReproducible demo link https://ww...
Issue #4704
Angular Component as Custom Color Picker is only created once
GrapesJS version [X] I confirm to use the latest version of GrapesJS What browser are you using? Version 104.0.5112.101 Reproducible demo l...
Issue #5718
Possible upgrade path issue where 'textnode' is now called 'wrapper' from 0.18 -> latest
GrapesJS version [X] I confirm to use the latest version of GrapesJS What browser are you using? Chrome Version 122.0.6261.95 (Official Bui...
Paid Plugins That Match This Issue
Curated by issue keywords and label relevance to help you ship faster.
Loading paid plugin recommendations...
Check the open-source GrapesJS plugins on GitHub or run a quick search in our free catalog.
Browse free plugins →Premium plugins ship with support, regular updates, and production-ready features — save days of integration work.
Browse premium plugins →Related tutorials
In-depth guides on the same topic.
Tutorial
Find the Right GrapesJS Plugin in Seconds: Smarter Discovery Is Live
We're shipping a set of discovery upgrades. New label filters, a proper compatibility switch for GrapesJS vs Studio, one-click and a smarter sort bar.
Tutorial
GrapesJS vs Webflow vs Tilda: What to Choose for Your Business in 2026
Choosing the right website platform in 2026 is no longer just about building a site
Tutorial
GJS Market 2.0 - Donations, Tracking, Labels and Better Product Discovery
We’ve rolled out a new set of GrapesJS marketplace updates across GJS Market, focused on improving how creators distribute products
Browse Plugin Categories
Jump directly to plugin category pages on the marketplace.