Skip to Content
PackagesCoreCommandsCommands: Tables

Commands: Tables

Commands for creating and editing tables: rows, columns, cells, layout, sorting and borders.

import { insertTable, insertRowBefore, setBorders } from "@stesura/core/commands";

Creating Tables

insertTable

Insert a table sized to the section’s content width, with the cursor in the first cell. Refused inside code blocks, inside another table, and wherever the schema cannot host a table (footnote/endnote bodies).

insertTable({ rows: number, cols: number, borders?: Borders | null // omit for default visible borders; null for borderless headerRowCount?: number // leading header rows; default 0 repeatHeaderRows?: boolean // repeat them on every page; default false }): Command

createTableNode

Build a table Node (not a command) for programmatic builders. Returns null when the schema lacks the table nodes.

createTableNode(state: EditorState, options: CreateTableOptions): Node | null type CreateTableOptions = { rows: number; cols: number; borders?: Borders | null; maxWidth?: number; // px to size the columns against; default: the section's content width // per-cell paragraph attrs and/or inline content cellParagraph?: (row: number, col: number) => { attrs?: Record<string, unknown>; content?: Node | Fragment | null } | undefined; };

Column Operations

insertColumnBefore / insertColumnAfter

Insert a column left / right of the selection, rescaling the existing columns so the table keeps its overall width. Refused when no column has a width to rescale.

insertColumnBefore: Command insertColumnAfter: Command

deleteColumn

Delete the selected columns and redistribute their width across the remaining ones. Refused when every column is selected. While track changes is enabled, the widths are not redistributed.

deleteColumn: Command

distributeColWidths

Set every selected column to width px. Omit width to give them their average width (needs 2+ columns). Floored at 25px.

distributeColWidths(width?: number): Command

Row Operations

insertRowBefore / insertRowAfter

Insert as many rows as the selection spans, above / below it. New cells copy the adjacent selected row’s cell attrs, including colspans, with empty content; above the first row they are plain cells. Rowspans crossing the insert point grow to cover the new rows.

insertRowBefore(updateSelection?: boolean): Command insertRowAfter(updateSelection?: boolean): Command

insertRow

The TransactionFn factory behind both commands, for custom insertions. It inserts rect.bottom - rect.top rows at row index row. copyRow picks the row whose cell attrs are copied: "bottom" the row at row, "top" the row above it, null for plain cells.

insertRow( rect: TableRect, row: number, copyRow: "bottom" | "top" | null, updateSelection?: boolean ): TransactionFn

deleteRow

Delete the selected rows. When the selection spans every row, delete the whole table instead. Deleting rows with vertically merged cells is not tracked (skipTrackChanges). deleteRowTr (in @stesura/core/commands/internal) is the transaction-level variant, without the whole-table case.

deleteRow: Command

setRowHeight

Set the height attr on every row covered by the selection, capped at the section’s page height. Pass null, or a value below the 30px minimum, to clear it. Refused when every row already has that height.

setRowHeight(height: number | null): Command

setRowKeepTogether

Set keepTogether (Word’s “Allow row to break across pages”, off) on every row covered by the selection. Pagination then moves such a row whole to the next page instead of splitting it, as long as it fits on one page. Refused when every row already has that value. getRowKeepTogetherFromSelection from @stesura/core/helpers reads it back: true only when every covered row keeps together.

setRowKeepTogether(keep: boolean): Command

Header Rows

A table’s leading headerRowCount rows are header rows: their cells render and serialize as <th scope="col">. A cell is a header cell when it starts in a header row; merging never promotes one. With repeatHeaderRows, pagination paints the header rows again at the top of every page the table continues onto (Word’s “Repeat Header Rows”), and keeps them whole. In DOCX, w:tblHeader carries both: header rows that don’t repeat export as body rows.

Row commands keep the count positional, as Word does with its per-row flag: rows inserted next to a header row (copying it) are header rows, deleted header rows leave the count, splitTable inside the header rows leaves both tables header rows, and sortTableRows leaves them on top. Edits that bypass the commands (a range delete, a paste, accepting a tracked row deletion) leave the count as it is. getHeaderRowCount(table) from @stesura/core/helpers reads the count clamped to the rows.

toggleHeaderRow

Make the first row a header row, or every header row a body row.

toggleHeaderRow: Command

setHeaderRowCount / setHeaderRowsToSelection

Set how many leading rows are header rows (clamped to the row count), or make every row down to the selection’s last one a header row (“Header rows end here”).

setHeaderRowCount(count: number): Command setHeaderRowsToSelection: Command

setRepeatHeaderRows

Turn repetition of the header rows on or off. Refused without header rows.

setRepeatHeaderRows(repeat: boolean): Command

Cells

mergeCells

Merge the selected cells into one. Only available when the selection’s outline forms a rectangle. The merge is not tracked (skipTrackChanges). mergeCellsTr in @stesura/core/commands/internal is the transaction-level variant and does not set skipTrackChanges.

mergeCells: Command

splitCell

Split a merged cell (rowspan or colspan > 1) back into single cells of its own type. The split is not tracked (skipTrackChanges). splitCellWithTypeTr(getCellType) in @stesura/core/commands/internal takes a custom cell-type resolver and does not set skipTrackChanges.

splitCell: Command

setCellAlignment

Align the selected cells’ content. The vertical half sets the cells’ verticalAlign; the horizontal half sets the text alignment of the blocks inside them.

setCellAlignment(alignment: `${"top" | "middle" | "bottom"}-${"start" | "center" | "end"}`): Command // setCellAlignment("top-start")

setCellAttr

Set attribute name on the selected cells. A dry run returns false when the cell already has value, unless returnTrueOnSameValue is set.

setCellAttr(name: string, value: unknown, returnTrueOnSameValue?: boolean): Command

Table Layout

setTableAlignment

Align the table within the section’s content width. Refused when the table already has that alignment.

setTableAlignment(alignment: "start" | "center" | "end"): Command

setTableSpacing

Merge spacing into the table’s space before/after; sides you leave out keep their value. Requires the whole table to be selected, as do the two commands below.

setTableSpacing(spacing: { before?: number; after?: number }): Command

setTableSpacingBeforeAfter

Set the spacing on one side.

setTableSpacingBeforeAfter({ position: "before" | "after", value: number }): Command

incrementTableSpacing

Add value to the spacing on one side, floored at 0.

incrementTableSpacing({ position: "before" | "after", value: number }): Command

Selection & Deletion

selectEntireTable

Select every cell of the table containing the selection, as a CellSelection. selectEntireTableAtPos(tablePos) targets the table at a known position.

selectEntireTable: Command selectEntireTableAtPos(tablePos: number): Command

deleteTable

Delete the table and put an empty paragraph in its place. deleteTableIfSelected runs only when the whole table is selected, so Delete inside a cell edits the cell instead.

deleteTable: Command deleteTableIfSelected: Command

Sorting

sortTableRows

Reorder all rows by one column’s text, compared as text, number or date according to orderBy. Empty or unparsable values sort last. Without options, it uses the table’s stored sort options, then { colIndex: 0, descending: false, orderBy: "text" }. It is refused, with a toast, when the table has any vertically merged cell or colIndex is out of range. It returns false when the rows are already sorted.

sortTableRows(options?: { colIndex: number; descending: boolean; orderBy: "text" | "number" | "date"; }): Command

setTableSortOptions

Store the sort options on the table (its sortable attr), so sortTableRows() can re-run later with the same settings.

setTableSortOptions(options: SortOptions): Command

Advanced

splitTable

Split the table in two at the cursor’s row, which becomes the first row of the second table. Refused on the first row and when a rowspan crosses that row.

splitTable: Command

Borders

setBorders applies borders to whatever the selection targets. It tries a selected horizontal rule, then a whole selected table, then cells, then styled blocks, and the first that applies wins.

import { setBorders } from "@stesura/core/commands"; setBorders(borders?: Borders): Command

setBordersTr(borders) in @stesura/core/commands/internal is the transaction-level variant.

Each side takes a BorderOptions:

type BorderOptions = { style: BorderStyle; // "single" | "dashed" | "dotted" | "double" | "groove" // | "ridge" | "inset" | "outset" | "none" color?: string; size?: number; space?: number; }; type Borders = { top?: BorderOptions; bottom?: BorderOptions; left?: BorderOptions; right?: BorderOptions; between?: BorderOptions; // blocks only insideHorizontal?: BorderOptions; // tables only insideVertical?: BorderOptions; // tables only };
// Horizontal rules on the selected cells, no verticals setBorders({ top: { style: "single", size: 1, color: "#000" }, bottom: { style: "single", size: 1, color: "#000" }, left: { style: "none" }, right: { style: "none" }, });

There is no "solid" style; the single-line style is "single". Use { style: "none" } to remove a side. A per-side null is only accepted on cell borders (CellBorders).

toggleOutline

Toggle the editor-wide outline overlay: dashed guides drawn where a block has no real border. Meta-only, so the doc is untouched.

toggleOutline: Command

insertHorizontalRule

Insert a horizontal_rule node at the selection.

insertHorizontalRule: Command

Next Steps

Last updated on