Skip to content

[lexical][lexical-overflow][lexical-react] Bug Fix: Make OverflowNode inline without the line break caret regression - #9461

Open
Vedthakar wants to merge 1 commit into
meta:mainfrom
Vedthakar:fix/9454-overflow-inline
Open

Vedthakar wants to merge 1 commit into
meta:mainfrom
Vedthakar:fix/9454-overflow-inline

Conversation

@Vedthakar

Copy link
Copy Markdown
Contributor

Description

This solves issue #9454.

OverflowNode is now inline (isInline() returns true), as #6027 first tried. #6535 reverted #6027 because, in plain-text mode or with Shift+Enter in rich text, a line break typed at the end of the overflow left the caret before the trailing LineBreakNode.

Root cause. Once OverflowNode is inline, a <br> ends up as the last thing inside an inline <span> at the end of a paragraph. Two things then go wrong:

  1. The reconciler adds a managed trailing <br> only when a block's direct last child is a LineBreakNode. Here the paragraph's last child is the OverflowNode, so no managed <br> is added and the new empty line has no caret position.
  2. After the character-limit plugin wraps the newly inserted line break and merges it into the existing overflow, the selection is an element point at the end of the OverflowNode, past its <br>. The browser can't put the caret there and moves it to before the overflow, so the next character goes in front of the 6. The test saw 76 instead of 6<br>7.

Changes

Closes #9454

Test plan

Before

  • isInline() alone (the Fix OverflowNode configuration #6027 configuration), packages/lexical-playground/src/__tests__/browser/CharacterLimit.test.ts (vitest browser, chromium): 6 failed | 10 passed (16). This is the Revert "Fix OverflowNode configuration" #6535 regression: the caret lands before the line break in plain text, and the delete text in front cases fail.
  • New unit tests in packages/lexical-react/src/__tests__/unit/useLexicalCharacterLimit.test.ts against main: 3 failed | 7 passed (10).
  • New core test in packages/lexical/src/__tests__/unit/LexicalReconciler.test.ts (a paragraph ending in a LinkNode whose last child is a LineBreakNode) against main: 1 failed. No managed <br> is rendered after the <a>.

After

On current main (tested together with my other open fixes):

  • useLexicalCharacterLimit.test.ts, LexicalReconciler.test.ts and NodeStructureExtension.test.ts: 131 passed (5 fail on main).
  • CharacterLimit.test.ts (browser, Chromium): 20 passed.
  • Chromium e2e: CharacterLimit.spec.mjs, Links.spec.mjs, Selection.spec.mjs and regression/1113-link-newline-at-end.spec.mjs pass.
  • pnpm run test-unit: all 10,080 tests pass
  • tsc, pnpm run flow (0 errors), and eslint/prettier on the changed files: clean

Author: Ved Thakar (@Vedthakar)

🤖 Generated with Claude Code

… inline without the line break caret regression

OverflowNode.isInline() now returns true (meta#6027, reverted in meta#6535).

The revert was caused by a trailing LineBreakNode inside the now inline
OverflowNode: the browser can't put the caret after a <br> that ends an
inline element, so the next character landed before the line break.

- The reconciler gives a block the managed trailing <br> when its last
  child is an inline element that itself ends with a LineBreakNode.
- $wrapOverflowedNodes moves a caret left at the end of an OverflowNode
  ending with a line break to the same spot just after the OverflowNode.

Closes meta#9454

Signed-off-by: Ved Thakar <111605341+Vedthakar@users.noreply.github.com>
Co-authored-by: Ved Thakar <111605341+Vedthakar@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@vercel

vercel Bot commented Oct 25, 2026 •

Copy link
Copy Markdown

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

Project Deployment Actions Updated
lexical Ready Ready Preview Oct 25, 2026 1:09am UTC
lexical-playground Ready Ready Preview Oct 25, 2026 1:09am UTC

Request Review

@pkg-pr-new

pkg-pr-new Bot commented Oct 25, 2026

Copy link
Copy Markdown
lexical

npm i https://pkg.pr.new/lexical@9461

@lexical/a11y

npm i https://pkg.pr.new/@lexical/a11y@9461

@lexical/clipboard

npm i https://pkg.pr.new/@lexical/clipboard@9461

@lexical/code

npm i https://pkg.pr.new/@lexical/code@9461

@lexical/code-core

npm i https://pkg.pr.new/@lexical/code-core@9461

@lexical/code-prism

npm i https://pkg.pr.new/@lexical/code-prism@9461

@lexical/code-shiki

npm i https://pkg.pr.new/@lexical/code-shiki@9461

@lexical/compiler

npm i https://pkg.pr.new/@lexical/compiler@9461

@lexical/devtools-core

npm i https://pkg.pr.new/@lexical/devtools-core@9461

@lexical/dragon

npm i https://pkg.pr.new/@lexical/dragon@9461

@lexical/eslint-plugin

npm i https://pkg.pr.new/@lexical/eslint-plugin@9461

@lexical/extension

npm i https://pkg.pr.new/@lexical/extension@9461

@lexical/fast-check

npm i https://pkg.pr.new/@lexical/fast-check@9461

@lexical/file

npm i https://pkg.pr.new/@lexical/file@9461

@lexical/hashtag

npm i https://pkg.pr.new/@lexical/hashtag@9461

@lexical/headless

npm i https://pkg.pr.new/@lexical/headless@9461

@lexical/history

npm i https://pkg.pr.new/@lexical/history@9461

@lexical/html

npm i https://pkg.pr.new/@lexical/html@9461

@lexical/internal

npm i https://pkg.pr.new/@lexical/internal@9461

@lexical/link

npm i https://pkg.pr.new/@lexical/link@9461

@lexical/list

npm i https://pkg.pr.new/@lexical/list@9461

@lexical/mark

npm i https://pkg.pr.new/@lexical/mark@9461

@lexical/markdown

npm i https://pkg.pr.new/@lexical/markdown@9461

@lexical/mdast

npm i https://pkg.pr.new/@lexical/mdast@9461

@lexical/offset

npm i https://pkg.pr.new/@lexical/offset@9461

@lexical/overflow

npm i https://pkg.pr.new/@lexical/overflow@9461

@lexical/plain-text

npm i https://pkg.pr.new/@lexical/plain-text@9461

@lexical/react

npm i https://pkg.pr.new/@lexical/react@9461

@lexical/rich-text

npm i https://pkg.pr.new/@lexical/rich-text@9461

@lexical/selection

npm i https://pkg.pr.new/@lexical/selection@9461

@lexical/table

npm i https://pkg.pr.new/@lexical/table@9461

@lexical/tailwind

npm i https://pkg.pr.new/@lexical/tailwind@9461

@lexical/text

npm i https://pkg.pr.new/@lexical/text@9461

@lexical/utils

npm i https://pkg.pr.new/@lexical/utils@9461

@lexical/yjs

npm i https://pkg.pr.new/@lexical/yjs@9461

commit: 46d1e96

This branch was successfully deployed

2 active deployments
Preview – lexical — 46d1e96b Deployed Oct 25, 2026 by vercel[bot]
Preview – lexical-playground — 46d1e96b Deployed Oct 25, 2026 by vercel[bot]
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.

[lexical-overflow] Make OverflowNode a proper inline element (revisit #6027 / #6535)

1 participant