Skip to content

fix(core): allow empty table rows so merging every cell doesn't add a column - #3151

Draft
adarshsm wants to merge 1 commit into
TypeCellOS:mainfrom
adarshsm:fix/1993-merge-all-table-cells
Draft

adarshsm wants to merge 1 commit into
TypeCellOS:mainfrom
adarshsm:fix/1993-merge-all-table-cells

Conversation

@adarshsm

@adarshsm adarshsm commented Oct 4, 2026

Copy link
Copy Markdown
Contributor

Summary

Closes #1993. If you select every cell in a table and merge them, you should get one cell spanning the whole table. Instead, each row gets a new empty cell in front of the merged one, so the table gains an extra column.

Rationale

prosemirror-tables' mergeCells deletes the merged-away cells and gives the remaining cell colspan = columns and rowspan = rows. That leaves rows 2..n with no cells, because the rowspan covers all of their positions. prosemirror-tables' own row spec is (table_cell | table_header)*, which allows those empty rows. That's also why the merge works in the prosemirror-tables demo, where @YousefED couldn't reproduce this.

BlockNote's tableRow uses (tableCell | tableHeader)+. So when mergeCells deletes the last cell of a row, ProseMirror fills the row with a new cell to keep the row valid. Those filler cells overlap the merged cell's rowspan, and the table ends up with the extra column.

Output for a 2×2 table on main, after merging all cells:

table(tableRow(tableCell(tableParagraph), tableCell[colspan=2,rowspan=2](...)), tableRow(tableCell(tableParagraph)))

With this change:

table(tableRow(tableCell[colspan=2,rowspan=2](...)), tableRow)

Changes

  • packages/core/src/blocks/Table/block.ts: change the tableRow content expression from + to *, matching prosemirror-tables, with a comment explaining why rows can be empty.
  • packages/core/src/blocks/Table/TableExtension.test.ts: a test that merges every cell of a 2×3 table. It checks that the result is one cell (colspan: 3, rowspan: 2), that the second row has no cells, and that there are still 3 column widths.

Impact

The schema only gets more permissive, so every existing document stays valid. A row covered by a rowspan from above shows up in the block API as { cells: [] }. That's the same as HTML, where a fully covered <tr> has no <td>s. I checked these paths with an empty row in a scratch test:

  • replaceBlocks round-trip
  • blocksToFullHTML / blocksToHTMLLossy (render <tr></tr>)
  • tryParseHTMLToBlocks (parses back to [1, 0] cells)
  • blocksToMarkdownLossy (fills in the grid)
  • splitCell on the merged cell (restores the full grid)

For the exporters: the ODT exporter already emits covered cells for empty rows through its coveredBelow walk, and the DOCX exporter passes rowSpan to docx.js, which inserts the vMerge continuation cells itself.

One thing to flag for collaboration: a client still on the old schema would treat a document with such an empty row as invalid. That only matters for mixed versions editing the same document.

Testing

  • The new test fails on main (row cell counts are [2, 1] instead of [1, 0]) and passes with the fix.
  • Full packages/core unit suite passes with the change (vp test --run, run with NODE_OPTIONS=--no-experimental-webstorage because of Node 26's built-in localStorage).
  • vp fmt --check and vp lint --type-aware are clean on the changed files.
  • I didn't run the Docker browser/e2e suite.

Checklist

  • Code follows the project's coding standards.
  • Unit tests covering the new feature have been added.
  • All existing tests pass.
  • The documentation has been updated to reflect the new feature (n/a)

🤖 Generated with Claude Code

… column

Merging all cells of a table left the rows below the first one with no
cells, since the merged cell's rowspan covers them. prosemirror-tables
expects that, and its own row spec is `(table_cell | table_header)*`.
BlockNote's `tableRow` required at least one cell, so ProseMirror filled
each emptied row with a new cell. Those filler cells collided with the
rowspan, and the table gained an extra column instead of becoming a
single cell.

Closes TypeCellOS#1993
@vercel

vercel Bot commented Oct 4, 2026

Copy link
Copy Markdown

@adarshsm is attempting to deploy a commit to the TypeCell Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai

coderabbitai Bot commented Oct 4, 2026

Copy link
Copy Markdown
Contributor

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

@pkg-pr-new

pkg-pr-new Bot commented Oct 4, 2026

Copy link
Copy Markdown

Open in StackBlitz

@blocknote/ariakit

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

@blocknote/code-block

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

@blocknote/core

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

@blocknote/diagram-block

npm i https://pkg.pr.new/@blocknote/diagram-block@3151

@blocknote/mantine

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

@blocknote/math-block

npm i https://pkg.pr.new/@blocknote/math-block@3151

@blocknote/react

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

@blocknote/server-util

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

@blocknote/shadcn

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

@blocknote/xl-ai

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

@blocknote/xl-docx-exporter

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

@blocknote/xl-email-exporter

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

@blocknote/xl-multi-column

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

@blocknote/xl-odt-exporter

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

@blocknote/xl-pdf-exporter

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

@blocknote/xl-typst-exporter

npm i https://pkg.pr.new/@blocknote/xl-typst-exporter@3151

commit: 62da67b

This branch has not been deployed

No deployments
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.

Table Cell Merge Bug - Extra Column Appears When Merging All Cells

1 participant