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.
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:
| Shortcut | Action |
|---|---|
⌘↩ / Ctrl+Enter | Insert row below |
⌘⇧↩ / Ctrl+Shift+Enter | Insert row above |
⌘⇧⌫ / Ctrl+Shift+Backspace | Delete row |
Tab in the last cell | Append 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 (
abovethere 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:
| Helper | Purpose |
|---|---|
$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, $setTableDensity | Single-setting variants |
parseTableSettingsMarker(line), formatTableSettingsMarker(settings, options?) | Comment line ⇄ TableSettings |
TABLE | The markdown transformer, if you assemble your own Lexical editor |
Types: TableCellPosition, TableDensity, TableSettings,
TableSettingsOptions, DEFAULT_TABLE_SETTINGS.