Skip to content

fix(table): prevent crash when pressing Enter in a table cell#2793

Open
y-temp4 wants to merge 2 commits into
TypeCellOS:mainfrom
y-temp4:fix/table-enter-split-crash
Open

fix(table): prevent crash when pressing Enter in a table cell#2793
y-temp4 wants to merge 2 commits into
TypeCellOS:mainfrom
y-temp4:fix/table-enter-split-crash

Conversation

@y-temp4
Copy link
Copy Markdown

@y-temp4 y-temp4 commented May 27, 2026

Summary

Fixes a crash where pressing Enter inside a table cell throws TransformError: Cannot join tableCell onto blockContainer and leaves the editor in an unrecoverable state.

Closes #2792.

Symptom & minimal reproduction

Reproducible on the official demo (no app-specific code needed): https://www.blocknotejs.org/demo#pwls9

  1. Open the demo (it contains a table).
  2. Click inside a cell in the last row.
  3. Press Enter → the editor crashes.

It also reproduces by:

  • selecting text within a last-row cell and pressing Enter;
  • selecting across multiple cells (a CellSelection) and pressing Enter.

Stack trace

TransformError: Cannot join tableCell onto blockContainer
  at new TransformError (prosemirror-transform)
  at Transaction.step (prosemirror-transform)
  at split (prosemirror-transform)
  at Transaction.split (prosemirror-transform)
  at splitBlockTr (packages/core/src/api/blockManipulation/commands/splitBlock/splitBlock.ts:55)  // tr.split(posInBlock, 2, types)
  at splitBlockCommand (.../splitBlock.ts:22)
  at KeyboardShortcutsExtension Enter handler (.../KeyboardShortcuts/KeyboardShortcutsExtension.ts:918)
      // chain().deleteSelection().command(splitBlockCommand(...)).run() — reached because the
      // table's Enter handler returned false and fell through to the default splitBlock

Cause

The table-specific Enter handler in packages/core/src/blocks/Table/TableExtension.ts (added in #2685, "feat: Enter moves selection to cell below in tables (BLO-1006)") only handles the case where a cell exists below the cursor. In several edge cases it returns false and falls through to the default splitBlock handler.

splitBlockTr resolves the nearest block container of a cell to the outer blockContainer that wraps the whole table (whose content — the table — is non-empty, so the "empty block" early-outs don't apply), and then calls tr.split(pos, 2, ...) at a position deep inside the cell. Splitting a tableCell at depth 2 is invalid, so ProseMirror throws Cannot join tableCell onto blockContainer.

Edge cases that triggered the fallback (and therefore the crash):

  1. Cursor in a cell on the last row (no cell below → !$nextCellfalse).
  2. A non-empty text selection inside a last-row cell.
  3. A multi-cell selection (CellSelection) — the selection head resolves to a tableRow, so the handler's previous $head.parent.type.name === "tableParagraph" guard was bypassed entirely.

Fix

  • Detect being inside a table with isInTable instead of checking that the cursor's parent is a tableParagraph. This also covers multi-cell selections, where the head resolves to a tableRow.
  • Move the selection to the cell below when there is one (existing behavior preserved).
  • Always consume the Enter key while inside a table, so it never falls through to the default splitBlock handler. On the last row, Enter is now a no-op.

Affected versions

@blocknote/core 0.51.2 and 0.51.3 (latest). The regression was introduced in 0.50.0 by #2685.

Tests

Adds packages/core/src/blocks/Table/TableExtension.test.ts with regression tests that:

  • confirm Enter still moves the selection to the cell below;
  • confirm Enter on the last row no longer crashes and is a no-op (table structure intact);
  • confirm a non-empty text selection in the last row no longer crashes;
  • confirm a multi-cell CellSelection no longer crashes.

All @blocknote/core tests pass (449 passed / 3 skipped), and lint + build (tsc) succeed.

Summary by CodeRabbit

  • Bug Fixes

    • Enter now consistently moves focus to the cell below when inside tables and consumes the Enter key to avoid unexpected behavior.
    • Pressing Enter on the last row (cursor, text selection, or multi-cell selection) no longer alters the document or causes issues.
  • Tests

    • Added tests covering Enter behavior across table positions and selection types.

Review Change Stack

…llOS#2792)

The table Enter handler added in TypeCellOS#2685 only handled the case where a cell
exists below the cursor. In several edge cases it returned `false` and fell
through to the default `splitBlock` handler, which resolves the nearest block
container of a cell to the outer `blockContainer` wrapping the whole table and
then calls `tr.split(pos, 2, ...)` deep inside the cell. Splitting a tableCell
this way is invalid and throws `TransformError: Cannot join tableCell onto
blockContainer`, crashing the editor.

The crashing edge cases were:
- cursor in a cell on the last row (no cell below);
- a non-empty text selection inside a last-row cell;
- a multi-cell `CellSelection` (the head resolves to a `tableRow`, bypassing
  the previous `tableParagraph` guard entirely).

Use `isInTable` to detect being inside a table (which also covers multi-cell
selections), move to the cell below when there is one, and always consume the
Enter key while inside a table so it never falls through to `splitBlock`. On
the last row Enter is now a no-op.

Adds regression tests covering all the crashing cases and confirming the
existing "move to cell below" behavior is preserved.

Closes TypeCellOS#2792

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@vercel
Copy link
Copy Markdown

vercel Bot commented May 27, 2026

@y-temp4 is attempting to deploy a commit to the TypeCell Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 27, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: a6ce08ca-7cd9-4871-a9ba-52484e8f7a07

📥 Commits

Reviewing files that changed from the base of the PR and between b4af8bb and c484155.

📒 Files selected for processing (2)
  • packages/core/src/blocks/Table/TableExtension.test.ts
  • packages/core/src/blocks/Table/TableExtension.ts
💤 Files with no reviewable changes (2)
  • packages/core/src/blocks/Table/TableExtension.test.ts
  • packages/core/src/blocks/Table/TableExtension.ts

📝 Walkthrough

Walkthrough

Refactors table Enter handling to always consume Enter inside tables and safely handle missing below-cells; adds Vitest tests that simulate Enter and verify selection moves for middle rows and no-op safe behavior for last-row cursor, text selections, and multi-cell selections.

Changes

Table Enter Key Behavior Fix

Layer / File(s) Summary
Enter handler fix
packages/core/src/blocks/Table/TableExtension.ts
Gates Enter handling with isInTable, safely finds current/next cell using selectionCell/nextCell, moves selection to the cell below only when present, and always returns true to consume Enter inside tables.
Test suite for Enter behavior
packages/core/src/blocks/Table/TableExtension.test.ts
Adds a Vitest/jsdom test module with pressEnter helper, a static test table, utilities to locate and set cursor/selection in cells, and tests that validate moving selection from middle rows and safe no-op behavior on last-row cursor, non-empty text selection, and multi-cell selection.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • TypeCellOS/BlockNote#2685: Prior implementation of Enter key behavior to move selection to the cell below in tables, which this PR refines and covers with tests.

Suggested reviewers

  • matthewlipski
  • nperez0111

Poem

🐰 In rows of cells I softly tread,
Press Enter wide — no crash, no dread.
From middle jump to the row beneath,
Last-row presses keep the doc complete.
Hooray — the table stays well-fed! 🎉

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The PR title clearly and concisely summarizes the main change: fixing a crash when pressing Enter in a table cell, which is the core objective of the PR.
Description check ✅ Passed The PR description is comprehensive and well-structured, covering the issue, root cause, fix approach, testing, and affected versions. It addresses the key sections with sufficient detail.
Linked Issues check ✅ Passed The code changes fully implement the fix described in issue #2792: using isInTable to detect table context, moving selection to cell below when available, and always consuming Enter to prevent falling through to splitBlock.
Out of Scope Changes check ✅ Passed All changes are directly related to fixing the table Enter key crash: modified TableExtension.ts to fix the handler logic and added comprehensive regression tests in TableExtension.test.ts.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@nperez0111 nperez0111 left a comment

Choose a reason for hiding this comment

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

This looks right to me, the AI generated comments are annoying though, they are not saying anything useful to someone reading the code now

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented May 27, 2026

Open in StackBlitz

@blocknote/ariakit

npm i https://pkg.pr.new/@blocknote/ariakit@2793

@blocknote/code-block

npm i https://pkg.pr.new/@blocknote/code-block@2793

@blocknote/core

npm i https://pkg.pr.new/@blocknote/core@2793

@blocknote/mantine

npm i https://pkg.pr.new/@blocknote/mantine@2793

@blocknote/react

npm i https://pkg.pr.new/@blocknote/react@2793

@blocknote/server-util

npm i https://pkg.pr.new/@blocknote/server-util@2793

@blocknote/shadcn

npm i https://pkg.pr.new/@blocknote/shadcn@2793

@blocknote/xl-ai

npm i https://pkg.pr.new/@blocknote/xl-ai@2793

@blocknote/xl-docx-exporter

npm i https://pkg.pr.new/@blocknote/xl-docx-exporter@2793

@blocknote/xl-email-exporter

npm i https://pkg.pr.new/@blocknote/xl-email-exporter@2793

@blocknote/xl-multi-column

npm i https://pkg.pr.new/@blocknote/xl-multi-column@2793

@blocknote/xl-odt-exporter

npm i https://pkg.pr.new/@blocknote/xl-odt-exporter@2793

@blocknote/xl-pdf-exporter

npm i https://pkg.pr.new/@blocknote/xl-pdf-exporter@2793

commit: b4af8bb

@y-temp4
Copy link
Copy Markdown
Author

y-temp4 commented May 27, 2026

Thanks for the review. I removed the redundant generated comments and kept only the required Vitest environment annotation.

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.

Bug: Pressing Enter in a table cell crashes the editor (TransformError: Cannot join tableCell onto blockContainer)

2 participants