Issue #4576πŸ’¬ AnsweredOpened September 12, 2022by benryanwilliams1 reactions

Clicking 'wrap for style' button affects the inner components of other components inside the same text box

Quick answerby artf❀ 1

RTE relies on the DOM content during the editing so if you remove it deliberately with something like inner components will be removed once the editing is finished.

Read full answer below ↓

Question

GrapesJS version

  • I confirm to use the latest version of GrapesJS

What browser are you using?

Chrome 104.0.5112.101

Reproducible demo link

https://jsfiddle.net/7cLr0xt2/3/

Describe the bug

How to reproduce the bug? For some reason I'm unable to reproduce the bug inside the fiddle linked above, since line 34 selectedComponent.components('<span liquid="if contact.id">jhbjhhgjjh</span> <span liquid="else">qwewqeqwe</span>') doesn't replace the inner components of the component, so I'll have to share a video of what happens with my project instead, but the steps are as follows:

  1. Double click on the Hello World!!! text box and select the word 'World'
  2. Click on the paintbrush button in the RTE editor to wrap that word for styling
  3. Click the circled 'if' button on the far left of the component toolbar and click 'ok' on the dialog that pops up to convert this to a 'conditional-text' component
  4. Double click on the newly created Open conditionals to choose component (normally this would bring up a dialog but I've simplified for the sake of this bug, so now it just applies some dummy information to the component, including adding an attribute and changing the inner components of the component. Changing the inner components doesn't work in this fiddle though, not sure why)
  5. Click the 'view code' button to see the changes that this has made to the code - as you can see it has inserted the attribute liquidtag="if", but the inner components do not appear. In my project, the inner components of this span would be <span liquid="if contact.id">jhbjhhgjjh</span> <span liquid="else">qwewqeqwe</span>
  6. Close the 'view code' dialog and double click the word Hello to select it
  7. Click the paintbrush button in the RTE editor to wrap that word for styling
  8. Click the 'view code' button again - in my project, the inner components ( i.e. <span liquid="if contact.id">jhbjhhgjjh</span> <span liquid="else">qwewqeqwe</span>) of the first component that we created in step (4) now disappear (the attributes remain though)

What is the expected behavior? Wrapping a word for styling shouldn't change the inner components of other components in that div. Presumably this is because of the way that 'wrap for style' works - perhaps it sets the inner HTML of that component to the same as the inner HTML of the component's view?

What is the current behavior? The inner components <span liquid="if contact.id">jhbjhhgjjh</span> <span liquid="else">qwewqeqwe</span> set in step 5 disappear and are replaced with the 'displayedText' property when another word in the original text box is wrapped for styling. I'm thinking it could be something to do with lines 85 - 87 in the fiddle, but as far as I understand this should only affect the view and therefore how it appears inside the canvas, not the underlying HTML of the component.

Here is a video showing what happens in my project:

https://user-images.githubusercontent.com/67364267/189606601-2f7b280e-8436-459f-8951-c55337123216.mov

Code of Conduct

  • I agree to follow this project's Code of Conduct

Answers (4)

artfβ€’ September 13, 2022

RTE relies on the DOM content during the editing so if you remove it deliberately with something like

onRender() {
  this.el.innerHTML = this.model.get("displayedText")
},

inner components will be removed once the editing is finished.

benryanwilliamsβ€’ September 13, 2022

Ok thanks @artf, that makes sense.

However, those lines of code, along with

init() {
        this.listenTo(this.model, "change:displayedText", this.render)
      },

are required to render the correct selected state inside the canvas as follows (both upon the component initially being rendered and when the user selects a different 'if' state, thus changing displayedText):

https://user-images.githubusercontent.com/67364267/189854125-9544d34b-2f71-4b0c-872e-dbdfb2232fd9.mov

Can you think of a way to retain the inner components after editing via RTE? Perhaps I could store these inner components inside a property of the conditional-text component itself and assign these during onRender() also? If that's possible, how can I set the component's components property within the onRender() hook?

Thanks for your help!

benryanwilliamsβ€’ September 13, 2022

I need to do some more testing but it looks like I've got around this behaviour by saving the inner components inside the component itself when first creating it / editing it, then using the rte:disable hook as follows:

editor.on('rte:disable', () => { 
          const conditionalComponents = (editor.getSelected().components().filter((component) => {
            return component.attributes.type == 'conditional-text'
          }))

          conditionalComponents.forEach((component) => {
            component.components(component.attributes.conditionCode)
          })
});

It seems a bit hacky so if you can think of a better way then please let me know.

ClaudeCodeβ€’ May 17, 2026

Thanks for reporting this, @benryanwilliams.

Great question about Clicking 'wrap for style' button affects the inner components of other components inside the same text box. The recommended approach with ProseMirror is to use the event-driven API.

Start here:

  1. Check the GrapesJS documentation for your specific module
  2. Look for the on() event listener method
  3. Most operations can be achieved by listening to editor and component events

Common patterns:

// Listen for changes
editor.on('change', () => console.log('something changed'));

// Component lifecycle
editor.on('component:mount', (c) => console.log('component ready', c));
editor.on('component:update', (c) => console.log('component updated', c));

If you're still stuck:

  • Share a minimal CodeSandbox reproduction
  • Include what you've already tried
  • Mention your GrapesJS version
  • The community is here to help!

Related Questions and Answers

Continue research with similar issue discussions.

Paid Plugins That Match This Issue

Curated by issue keywords and label relevance to help you ship faster.

View all plugins

Loading paid plugin recommendations...

Free option

Check the open-source GrapesJS plugins on GitHub or run a quick search in our free catalog.

Browse free plugins β†’
Premium option

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.

All tutorials β†’

Browse Plugin Categories

Jump directly to plugin category pages on the marketplace.