Skip to content

Conversation

@Jynx2004
Copy link

@Jynx2004 Jynx2004 commented Dec 16, 2025

Description

This PR fixes an issue where cursor navigation becomes inconsistent when a table is the final block in the document.

Fixes #7999

Problem

When a table is the last node and all content after it is deleted:

  • Clicking to the right of the table briefly places the cursor there, then moves it back into the last table cell
  • Repeatedly pressing the right arrow key causes the cursor to loop between:
    • The last table cell
    • A block cursor beneath the table
    • The right-hand side of the table
  • Pressing Enter while the cursor appears on the right-hand side of the table inserts a new paragraph above the table instead of below it

This makes it difficult for users to understand how to add content after a table.

Cause

When there is no text in the direction of navigation, Lexical attempts to explore adjacent nodes. If the previous node is a table, this logic re-enters table selection and causes the cursor to cycle back into the table.

Fix

Short-circuit navigation/deletion logic when:

  • There is no text in the navigation direction, and
  • The immediately preceding node is a table

This prevents Lexical from re-entering table selection logic and allows the cursor to correctly move and remain below the table.

Result

  • Cursor moves beneath the table when navigating right from the last cell
  • Cursor no longer cycles back into the table
  • Pressing Enter inserts a paragraph after the table
  • Matches expected behavior of common rich-text editors

Impact

Primarily a polish improvement, but significantly improves usability and prevents user confusion when editing content after tables.

@vercel
Copy link

vercel bot commented Dec 16, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Review Updated (UTC)
lexical Error Error Dec 18, 2025 6:23pm
lexical-playground Error Error Dec 18, 2025 6:23pm

@meta-cla meta-cla bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Dec 16, 2025
Copy link
Collaborator

@etrepum etrepum left a comment

Choose a reason for hiding this comment

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

This isn't a complete workaround and it does not add any tests to show that it works as expected

Comment on lines 1750 to 1751
const elementBefore =
anchorNode.__prev && $getNodeByKey(anchorNode.__prev);
Copy link
Collaborator

Choose a reason for hiding this comment

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

This is better written as anchorNode.getPreviousSibling()

Copy link
Author

@Jynx2004 Jynx2004 Dec 18, 2025

Choose a reason for hiding this comment

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

In my latest merge request i have used anchorNode.getPreviousSibling() instead of anchorNode.__prev and $getNodeByKey(anchorNode.__prev)

Comment on lines 1758 to 1760
if (elementBefore && elementBefore.__type === 'table') {
return;
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

This is not an acceptable solution because LexicalSelection shouldn't know about tables and the type of a table could be any string (in situations where a node override is used to replace TableNode with a subclass)

Copy link
Author

Choose a reason for hiding this comment

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

How can we identify the paragraph node which is just after the table in hierarchy other than the above method ?
If we recognize it then we can prevent deletion of it which resolves the bug.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Usually this would be done by implementing the functionality in one of the table plugins.

Copy link
Author

@Jynx2004 Jynx2004 Dec 18, 2025

Choose a reason for hiding this comment

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

Will work on improving elementBefore && elementBefore.__type === 'table'

Copy link
Author

Choose a reason for hiding this comment

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

The function $TableNode checks whether a given node is an instance of class TableNode but we cannot use it in LexicalSelection .

Copy link
Author

Choose a reason for hiding this comment

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

Usually this would be done by implementing the functionality in one of the table plugins.

Issue lies in the paragraphNode which is inserted below the table when the table is created . When we delete the paragraph then the cursor gets stuck in a loop when we click the right arrow. So we need to prevent the deletion of that node so that the bug gets resolved.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Right, this workaround should not be in this file at all.

Removed comments regarding deletion prevention before a table.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: Odd selection behavior with table as last element in document

2 participants