Skip to content

Handle contenteditable paste as plain text#1650

Open
pawfrolow wants to merge 18 commits into
josdejong:developfrom
pawfrolow:change_contenteditable_to_plained_text
Open

Handle contenteditable paste as plain text#1650
pawfrolow wants to merge 18 commits into
josdejong:developfrom
pawfrolow:change_contenteditable_to_plained_text

Conversation

@pawfrolow
Copy link
Copy Markdown
Contributor

I made separate PR, according to commend #1646 (comment)

2: Sometimes by pasting text from somewhere it pastes as html, and you couldn't use cursor to change value.
I've replaced "true" to "plaintext-only" value of contenteditable attribute, which indicates that the element's raw text is editable, but rich text formatting is disabled. (Link to mdn docs) And it works correctly

Copy link
Copy Markdown
Owner

@josdejong josdejong left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks Pavel, really nice to finally start using plaintext-only 🎉.

I made two inline comments, can you have a look at them?

Comment thread src/js/Node.js Outdated
Comment thread src/js/treemode.js Outdated
Copy link
Copy Markdown
Owner

@josdejong josdejong left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the updates. I did some more testing, and on old versions of Firefox this works fine now.

However, there seems to be a serious issue with Chrome: it doesn't process newline characters correctly anymore. For example:

  • Open the editor
  • Edit a value, clear it
  • Then, type "hello", Enter, Enter, "world", Enter.
  • Now, when leaving the value, the text should be changed into proper JSON: "hello\n\nworld\n"
  • On Chrome though, nothing seems to change, but when switching to text mode or getting the JSON contents from the editor, the text is changed into "helloworld": we have lost the newline characters.

This has to do with the way we retrieve the text contents from the editable div. The Editor uses a helper function getInnerText which iterates over the DOM. We can look into using div.innerText, but this has an issue with adding a trailing \n in some but not all cases, making it impossible to recognize an empty string vs a string containing one newline, vs a line with two newlines.

Alternatively, can try to extend the helper function getInnerText to handle the changed way that Chrome formats the DOM in case of using newlines. I think though that we will hit the very same issue as when using div.innerText.

I'm not sure how to solve this issue. Any ideas?

@pawfrolow
Copy link
Copy Markdown
Contributor Author

Thanks for the updates. I did some more testing, and on old versions of Firefox this works fine now.

However, there seems to be a serious issue with Chrome: it doesn't process newline characters correctly anymore. For example:

  • Open the editor
  • Edit a value, clear it
  • Then, type "hello", Enter, Enter, "world", Enter.
  • Now, when leaving the value, the text should be changed into proper JSON: "hello\n\nworld\n"
  • On Chrome though, nothing seems to change, but when switching to text mode or getting the JSON contents from the editor, the text is changed into "helloworld": we have lost the newline characters.

This has to do with the way we retrieve the text contents from the editable div. The Editor uses a helper function getInnerText which iterates over the DOM. We can look into using div.innerText, but this has an issue with adding a trailing \n in some but not all cases, making it impossible to recognize an empty string vs a string containing one newline, vs a line with two newlines.

Alternatively, can try to extend the helper function getInnerText to handle the changed way that Chrome formats the DOM in case of using newlines. I think though that we will hit the very same issue as when using div.innerText.

I'm not sure how to solve this issue. Any ideas?

Hi @josdejong, i came back with another solution :)

I looked into the plaintext-only a bit more, and I think it introduces more risk than it removes in this code.

The main issue is that the editor does read values through the custom getInnerText helper. That helper is tuned to the DOM structure produced by regular contenteditable=true. With plaintext-only, Chrome appears to produce a different text/DOM structure for multiline content, and we start losing newline when reading the value back.

So instead of continuing with plaintext-only, I changed the approach to a safer variant:
Keep using contenteditable=true, intercept paste, read text/plain from clipboard and insert that as plain text into the editable element

This fixes the original issue of pasted HTML ending up inside the editor, while keeping the existing newline handling and value parsing behavior intact.

I think this is better here because:

  • it solves the actual bug directly: rich HTML paste
  • it avoids browser-specific differences of plaintext-only
  • it does not require rewriting getInnerText
  • it keeps existing editing behavior for Enter/newlines unchanged

@pawfrolow pawfrolow changed the title Change contenteditable "true" to "plaintext-only" Handle contenteditable paste as plain text Apr 8, 2026
@josdejong
Copy link
Copy Markdown
Owner

That is an interesting idea, it makes sense. I'll look into your PR as soon as I have time.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants