Skip to content

Bug: Editor freezes when pasting text copied from websites into a nested editor state #7635

Closed

Description

@johnnyoshika

The editor consistently freezes when pasting text copied from websites into a nested editor state.

Lexical version: Observed in v0.30.0 and v0.32.1

Steps To Reproduce

  1. Go to https://playground.lexical.dev/
  2. Delete everything and insert sample image
  3. Add caption
  4. Type something into the caption (e.g. foo bar)
  5. Delete what you typed into the caption
  6. Copy text from somewhere in github.com (e.g. some random text from a GitHub issue)
  7. Paste it into the image caption in Lexical Playground (note: image caption is a nested editor state)
  8. The editor is now frozen

Demo video:

20250620-1549-37.0186866.mp4

The current behavior

Pasting text from websites into the editor causes it to freeze.

The expected behavior

Pasting text from websites doesn't cause the editor to freeze.

Impact of fix

This is a very severe bug. We use nested editor states in several custom Lexical plugins. Our users commonly paste content into them, which causes the editor to freeze and become unusable.

Activity

  1. changed the title [-]Bug: Editor freezes when pasting text copied from websites[/-] [+]Bug: Editor freezes when pasting text copied from websites into a nested editor state[/+] on Jun 20, 2025
  2. etrepum commented on Jun 20, 2025

    @etrepum
    Collaborator

    Are you able to reproduce this anywhere other than an image caption?

  3. etrepum commented on Jun 20, 2025

    @etrepum
    Collaborator

    I'm afraid you'll have to be more precise about what content exactly causes this issue. I could not reproduce given the instructions. The video attachment also isn't loading. A tool like Clipboard Inspector will allow you to inspect exactly what content is on your pasteboard, the text/html data would be relevant here.

  4. johnnyoshika commented on Jun 20, 2025

    @johnnyoshika
    Author

    Are you able to reproduce this anywhere other than an image caption?

    I can reproduce this anywhere where there's an embedded editor state. We've built 8 plugins that use that and the same problem happens in all of them.

  5. johnnyoshika commented on Jun 20, 2025

    @johnnyoshika
    Author

    I'm afraid you'll have to be more precise about what content exactly causes this issue. I could not reproduce given the instructions. The video attachment also isn't loading. A tool like Clipboard Inspector will allow you to inspect exactly what content is on your pasteboard, the text/html data would be relevant here.

    I've uploaded the demo video here: https://drive.google.com/file/d/14w4iTCAdoZlQSutbSHe0A0tYY77RElmk/view?usp=sharing

    I'll also try Clipboard Inspector to inspect what's in the clipboard.

  6. johnnyoshika commented on Jun 20, 2025

    @johnnyoshika
    Author

    @etrepum I copied some text from your message above and used Clipboard Inspector. It shows this:

    text/plain

    I'm afraid you'll have to be more precise
    

    text/html

    <html>     <body>     <!--StartFragment--><span style="color: rgb(240, 246, 252);   font-family: -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;,   &quot;Noto Sans&quot;, Helvetica, Arial, sans-serif, &quot;Apple   Color Emoji&quot;, &quot;Segoe UI Emoji&quot;; font-size: 14px;   font-style: normal; font-variant-ligatures: normal; font-variant-caps:   normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align:   start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px;   -webkit-text-stroke-width: 0px; white-space: normal; background-color:   rgb(13, 17, 23); text-decoration-thickness: initial; text-decoration-style:   initial; text-decoration-color: initial; display: inline !important; float:   none;">I'm afraid you'll have to be more precise<span>   </span></span><!--EndFragment-->     </body>     </html>
    

    Pasting this into the caption of the image (after adding text then deleting it) freezes the editor.

  7. etrepum commented on Jun 21, 2025

    @etrepum
    Collaborator

    Okay, so the description of this bug "Editor is now frozen" is the part that wasn't clear until seeing the video. "Editor is now frozen" means that the caption is still completely editable, the browser is still interactive, but the parent editor no longer works correctly. Normally when people say that the editor is frozen there is some sort of infinite loop or exception that occurs on any interaction.

  8. etrepum commented on Jun 21, 2025

    @etrepum
    Collaborator

    A quick look into this issue it seems that the problem is that the way Lexical handles commands with nested editors is a bit error prone.

    • $insertGeneratedNodes dispatches SELECTION_INSERT_CLIPBOARD_NODES_COMMAND to see if something wants to handle the paste, and if not, it will call selection.insertNodes
    • The payload of SELECTION_INSERT_CLIPBOARD_NODES_COMMAND has a selection property which is a BaseSelection.
    • The BaseSelection is implicitly bound to the editor it was created in (the keys make no sense in any other editor, will always be missing)
    • triggerCommandListeners (what editor.dispatchCommand does under the hood) dispatches the command to the intended editor and all of its ancestors until some listener returns true
    • The only thing listening to this command in the playground is the table plugin that will not do anything in the image caption (it's not installed there) but will get called from the parent editor
    • When the parent editor gets this command it tries to use the selection and fails, but in a quiet way because of lexical's "helpful" error suppression
    • I think at this point the selection isn't restored correctly in the parent editor and it gets broken forever for that reason (detecting and fixing this broken state can/should be separately fixable)

    There are a couple ways to fix the root cause:

    1. The targeted "just fix the bug" way without breaking changes is to have these table helpers check the second argument in their command listeners to see if the editor is the one that the listener was registered to and if not then exit early (return false in this case because $insertGeneratedNodes will not work correctly if return true happens). This leaves the opportunity for other code (not distributed in lexical) to have this same bug. [lexical-table] Bug Fix: Ignore SELECTION_INSERT_CLIPBOARD_NODES_COMMAND dispatched from child editors #7637 implements this minimal fix (will write tests before moving it out of draft state).
    2. The more robust fix would be to add some editor priority listener that does the selection.insertNodes and returns true (preventing dispatch to the parent) instead of having $insertGeneratedNodes inspect the return value (which requires dispatching through all parent editors as-is since false is the expected value). This would have to be part of the RichText/PlainText plugins since there's no "clipboard" plugin for this to belong to, and the priority level of the listener in registerTablePlugin would have to be bumped up from editor to low because commands are evaluated in priority descending and then registration ascending order. This is backwards incompatible mostly due to the priority issue, since we don't know if people have written their own editor priority handlers for this command and if they have they would be rendered useless by this strategy.
    3. Remove command forwarding altogether and have this be opt-in (e.g. an editor priority listener could explicitly re-dispatch to the parent editor if that's useful for a particular command). This is obviously more of a breaking change, but would make this entire class of bug opt-in.
  9. johnnyoshika commented on Jun 22, 2025

    @johnnyoshika
    Author

    @etrepum Thank you so much for this investigation and detailed explanation. Thank you also for the quick PR to fix this -> simply amazing!

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions