Skip to main content

Tables

Type a | a | b | row or use the toolbar's insert-table button. Tables round-trip as GFM pipe tables:

| Metric | Q1 | Q2 |
| --- | --- | --- |
| Revenue | $1.2M | $1.8M |

Rendering: rounded outer border, shaded header row. Editing is in place: Tab / arrows between cells, cell range selection, inline formatting inside cells. Cell content is single-line in markdown; newlines are escaped as \n.

Loading editor

Rows and columns

Click into a table and two slim rails appear: one along its left edge for rows, one along its top edge for columns. A bar on each marks the row and column the caret is in, and a + handle rests after the last row / column: click it to append one.

Move the pointer over a rail and the handle follows it:

  • near a boundary it is a + that inserts there; hovering previews the insertion as a line across the table
  • over the middle of a row or column it becomes a that removes it; hovering tints what will go

The caret moves into whatever was inserted.

Keyboard

Inside a table:

ShortcutAction
⌘↩ / Ctrl+EnterInsert row below
⌘⇧↩ / Ctrl+Shift+EnterInsert row above
⌘⇧⌫ / Ctrl+Shift+BackspaceDelete row
Tab in the last cellAppend a row

Header invariants

GFM tables have exactly one header row, the first, and rows of equal length. The editor keeps that shape:

  • nothing is inserted above the header row (above there inserts right below the header)
  • deleting the header row makes the next row the header, so the markdown keeps its divider line
  • a new column gets a header cell in the header row
  • the last remaining row or column can't be deleted

Width and density

Place the caret in a table and a small toolbar floats above its top-right corner (stacked over the column rail) with the table's width (full, text, content, see Layout) and its density: compact, comfortable (default) or spacious cell padding and font size.

Non-default settings are persisted as one HTML comment on the line directly above the table. Other markdown renderers hide it:

<!-- width: content; density: compact -->
| Key | Value |
| --- | --- |
| Region | eu-west-1 |

A width-only table gets <!-- width: content -->. Unknown keys and values are ignored (a width the editor does not know is treated as full), so documents written by a newer version still open.

Programmatic access

From useMarkdownEditor(): tableCell, insertTableRow('above' | 'below'), deleteTableRow(), insertTableColumn('before' | 'after'), deleteTableColumn(), tableDensity / setTableDensity, blockWidth / setBlockWidth.

Inside editor.update() / editor.read(), the node-level helpers:

HelperPurpose
$getSelectedTable(), $getSelectedTableCell()The table / cell containing the selection
$getTableCellPosition(cell)TableCellPosition for a cell node
$insertTableRowAt(table, index), $deleteTableRowAt(table, index)Absolute row operations
$insertTableColumnAt(table, index), $deleteTableColumnAt(table, index)Absolute column operations
$insertTableRowNear(position), $insertTableColumnNear(position)Selection-relative insertions
$deleteSelectedTableRow(), $deleteSelectedTableColumn()Selection-relative deletions
insertableRowIndices(position), insertableColumnIndices(position)Which indices an insertion may target (pure functions)
canDeleteRow(position), canDeleteColumn(position)Guard against deleting the last lane (pure functions)
$getTableSettings(node), $setTableSettings(node, settings, options?)Read / write width + density; { explicitWidth } writes full explicitly
$getTableWidth, $setTableWidth, $isTableWidthExplicit, $getTableDensity, $setTableDensitySingle-setting variants
parseTableSettingsMarker(line), formatTableSettingsMarker(settings, options?)Comment line ⇄ TableSettings
TABLEThe markdown transformer, if you assemble your own Lexical editor

Types: TableCellPosition, TableDensity, TableSettings, TableSettingsOptions, DEFAULT_TABLE_SETTINGS.