TextNodes interfere when changing content on element
Hi Juan, thanks for the report, are you able to show me how your text trait works? I'd expect it to work correctly if you update your component in this way component.components(e.target.value)
Read full answer below βQuestion
Version: 0.16.44
Hi @artf
I have a custom block with a custom button component, which its content is similar to this one.
<a data-gjs-type="custom_button" class="btn btn-1" href="">Click here</a>
Additionally, I've added a text trait to change the button content, in this particular case I do not want to use the editor RTE. <img width="286" alt="image" src="https://user-images.githubusercontent.com/1976679/109966677-d3a91180-7cf0-11eb-8463-e28b8de806c2.png">
When i change the value, the first time it gets reflected correctly <img width="975" alt="image" src="https://user-images.githubusercontent.com/1976679/109967201-6c3f9180-7cf1-11eb-943e-0c96e8693845.png">
But when i save and reload the page again, it gets back to its original value <img width="967" alt="image" src="https://user-images.githubusercontent.com/1976679/109967439-b6287780-7cf1-11eb-8c81-053458c1dc38.png">
This is happening in the updateContent function of the component view, the component is checking if it has children, in that case, the component does not render the content, the element has children, but they are text nodes.
Also if you set the content beforehand as a component configuration attribute, it does this.
<img width="972" alt="image" src="https://user-images.githubusercontent.com/1976679/109968113-9180cf80-7cf2-11eb-9d5a-961d0fe78237.png">The toHtml function of the Component model first prints the content and then its children (the text nodes).
In my case i have solved this by overriding the renderChildren and toHtml functions in view and model of my custom component, also removing the default text of the tag directly and adding it to the component configuration only. I'm writing this because maybe the case goes beyond my particular situation and can cause other problems.
For what I've seen the text nodes are a little tricky to handle. When i have some time i can go back to this again and provide a
Answers (4)
Hi Juan, thanks for the report, are you able to show me how your text trait works?
I'd expect it to work correctly if you update your component in this way component.components(e.target.value)
This was my trait
tm.addType('content', {
events: {
'change': 'onValueChange'
},
getInputEl: function() {
this.inputEl = document.createElement('input');
this.inputEl.value = this.getModelValue();
return this.inputEl;
},
getModelValue: function() {
const { model, target } = this;
var value = target.get('content') || target.getEl().textContent;
return value;
},
onValueChange: function() {
const { model, target } = this;
var value = this.inputEl.value;
target.set('content', value);
target.getEl().textContent = value;
},
onUpdate: function() {
var value = this.getModelValue();
this.target.getEl().textContent = value;
}
});
I have changed it to
tm.addType('content', {
events: {
'change': 'onValueChange'
},
getInputEl: function() {
this.inputEl = document.createElement('input');
this.inputEl.value = this.getModelValue();
return this.inputEl;
},
getModelValue: function() {
const { model, target } = this;
var value = target.get('content') || target.getEl().textContent;
return value;
},
onValueChange: function() {
const { model, target } = this;
var value = this.inputEl.value;
target.set('content', value);
target.components(value);
},
onUpdate: function() {
var value = this.getModelValue();
this.target.getEl().textContent = value;
}
});
And now it works without overriding update content or render children, thanks! I would have never arrived to the conclusion of using the components method. Now i don't like text nodes π
I think we can close this issue unless there's some other point you want to add to improve.
Thanks!
I don't think you need this one target.set('content', value);. For the rest all good π
Thanks for reporting this, @jcamejo.
Thanks for sharing your report about TextNodes interfere when changing content on element. To help the team investigate and prioritize this:
Please provide:
- A minimal reproducible example (CodeSandbox/JSFiddle)
- Your GrapesJS version number
- Browser and OS information
- Any error messages from the browser console
- Steps to reproduce the issue
What helps most:
- Minimal code example (not your full project)
- Screen recording or screenshot showing the issue
- Expected vs actual behavior clearly stated
- GrapesJS configuration you're using
With these details, the maintainers can identify and prioritize a fix much faster. The GrapesJS team is very responsive to well-documented issues.
Related Questions and Answers
Continue research with similar issue discussions.
Issue #3500
Remove custom trait by its type.
I have created a custom trait but the name of that trait will be dynamic which is unknown. The problem is that the current removeTrait() on...
Issue #3546
How can I add the custom left toolbar for Image component similar to text
We want to add a custom toolbar to the image component to be shown at left side (similar to what we show for text component). Please let me...
Issue #3732
comment component type do not support adding traits
i am working on a script that add a trait on all the component type , but the comment type do not have the prototype object. code
Issue #3507
No Generated ID and No auto select ID
Hi Guys, I am using grapesjs-blocks-bootstrap4 and I check how they component it's looks fine. But when you select block like container it...
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
Big Updates: TinyMCE 8 and Placeholder 2.0 for GrapesJS
In May we shipped major updates to two of our most popular GrapesJS plugins β TinyMCE Inline Text Editor and Placeholder.
Tutorial
GrapesJS vs Webflow vs Builder.io vs Puck: Which Visual Builder to Choose in 2026
A practitioner's 2026 comparison of GrapesJS, Webflow, Builder.io, and Puck β pricing, AI features, lock-in, and a one-line rule for picking the right one
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.
Browse Plugin Categories
Jump directly to plugin category pages on the marketplace.