Skip to content

Table handles assume any hovered TD/TH belongs to a table block — crashes on custom blocks that render a real <table> #2964

Description

@skcc-jeongheeseok

Summary

TableHandlesView.mouseMoveHandler decides a block is a table from the DOM alone, then checks only that the schema contains a table block — never that the hovered block is one. Any custom block that renders a real <table> therefore ends up on the table path, and reading its content throws.

Still present in 0.53.0 (found on 0.51.4, verified the same code in the latest).

Where

packages/core/src/extensions/TableHandles/TableHandles.ts

// L212 — the block is decided by walking up the DOM to a TD/TH
const target = domCellAround(event.target);

// L262
if (!pmNodeInfo) throw new Error(`Block with ID ${blockEl.id} not found`);

// L274 — asks whether the *schema* has a table, not whether *this block* is one
if (editorHasBlockWithType(this.editor, "table")) {
  this.tablePos = ;
  tableBlock = block;
}

// L339
colIndex === tableBlock.content.rows[0].cells.length - 1,

domCellAround returns {type: "cell"} for any TD/TH. Its .ProseMirror bail-out never runs when the event target already is a cell, so nothing an integrator puts on an ancestor can opt out.

Two ways this fires

1. A custom block with content: "none" that renders a tableblock.content is undefined:

Uncaught TypeError: Cannot read properties of undefined (reading 'rows')

Merely moving the mouse across the cells is enough — no click, no edit. In our app (an embedded database view drawn inside a document) this filled the console with one error per mouse move.

2. A table inside a nested editor (our synced-block feature embeds a second BlockNote editor in a custom block). The cell belongs to the inner editor, but the outer editor's handler still matches it because this.pmView.dom.contains(event.target) is true, and the id is unknown to the outer document:

Uncaught Error: Block with ID <id> not found

Minimal reproduction

  1. Add a custom block spec with content: "none" whose render function returns a plain <table><tbody><tr><td>x</td></tr></tbody></table>.
  2. Insert it into a document.
  3. Move the mouse over the cell.

Suggested fix

After resolving the hovered block, check the block itself rather than the schema — e.g. block.type === "table" (or checkBlockIsDefaultType("table", block, this.editor)) — and return early otherwise. The same early return would cover the nested-editor case if the id lookup fails instead of throwing.

Workaround we are using

We wrap mouseMoveHandler and, when the cell is not a real table cell of this editor, call the original with the event's target proxied to the editor root: domCellAround then stops at .ProseMirror and reports "no table", which is the path that hides the handles. Swallowing the event instead is not viable — column resizing listens on window, so stopPropagation breaks it.

Related: #1411 (the colIndex variant, closed without a reproduction).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions