prosemirror-tables

repository·master·Indexed 43 days ago

https://github.com/prosemirror/prosemirror-tables

A ProseMirror module providing schema extensions, plugins, and commands for complex tables. It includes support for rowspan/colspan, cell selection via CellSelection, table structural integrity, and a column resizing plugin. Version 1.8.5.

Tokens
9.8K
Snippets
37
Records
52
Agent score
50%

What's inside ProseMirror Tables

  1. Understand `TableMap` for table structure

    master

    A TableMap is a cached representation of a table's structure. It uses positions relative to the start of the table (rather than the document) to allow for efficient caching per table node.

    Properties

    • width: The number of columns in the table.
    • height: The number of rows in the table.
    • map: A flat array of size width * height containing the start position of the cell covering each slot.

    Methods

    • static get(table: Node): Retrieves the TableMap for a specific table node.
    • findCell(pos: number): Returns the Rect (dimensions) of the cell at the given position.
    • colCount(pos: number): Returns the left-side column index of the cell at the given position.
    • nextCell(pos: number, axis: string, dir: number): Finds the next cell in the specified axis and dir.
    • rectBetween(a: number, b: number): Returns the Rect spanning the two given cells.
    • cellsInRect(rect: Rect): Returns an array of positions for all cells whose top-left corner is within the given rectangle.
    • positionAt(row: number, col: number, table: Node): Returns the position where a cell at the specified row/column would start.
  2. Initialize the column resizing plugin

    master

    Use the columnResizing function to create a ProseMirror plugin that enables users to resize table columns by dragging handles. You can configure the handle width, minimum cell widths, and whether the last column is resizable.

    import { columnResizing } from 'prosemirror-tables';
    
    const plugin = columnResizing({
      handleWidth: 5,
      cellMinWidth: 25,
      defaultCellMinWidth: 100,
      lastColumnResizable: true
    });
  3. Enable table editing with the `tableEditing` plugin

    master

    The tableEditing plugin enables essential table functionality, including:

    • Cell-based selection
    • Cell-based copy/paste
    • Automatic enforcement of table invariants (e.g., ensuring rows have consistent widths and cells do not overlap)

    Note on Plugin Ordering: It is recommended to place tableEditing() near the end of your plugin array. Because it handles mouse and arrow key events broadly, other specialized plugins (like gapcursor or column-width dragging plugins) should be placed before it to ensure they can intercept specific interactions first.

    import { tableEditing } from "prosemirror-tables";
    
    const plugins = [
      // ... other plugins (e.g., gapcursor)
      tableEditing()
    ];
  4. Create a table-enabled schema with `tableNodes`

    master

    To support tables with rowspan and colspan in your ProseMirror schema, use the tableNodes function to generate the necessary node specs for table, table_row, and table_cell nodes. The resulting object can be merged into your schema's node definitions.

    Options

    OptionTypeDescription
    tableGroup?stringA group name (e.g., "block") to add to the table node type.
    cellContentstringThe content expression allowed inside table cells.
    cellAttributes?ObjectAdditional attributes for cells. Maps attribute names to objects containing:
        - defaultanyThe attribute's default value.
        - getFromDOM?fn(dom.Node) → anyFunction to read the attribute from a DOM node.
        - setDOMAttr?fn(value: any, attrs: Object)Function to add the attribute to the cell's DOM attributes.
    // Example usage of tableNodes (conceptual)
    const nodes = {
      ...otherNodes,
      ...tableNodes({
        tableGroup: 'block',
        cellContent: 'block+'
      })
    };
    const schema = new Schema({ nodes, content });
  5. Configure ColumnResizingOptions

    master

    The columnResizing function accepts an optional ColumnResizingOptions object to customize the resizing behavior:

    OptionTypeDefaultDescription
    handleWidthnumber5The width of the interactive area at the edge of a cell used to trigger resizing.
    cellMinWidthnumber25The absolute minimum width a cell/column can be resized to.
    defaultCellMinWidthnumber100The default minimum width applied to cells/columns that do not have an explicit colwidth attribute.
    lastColumnResizablebooleantrueIf false, the last column of a table cannot be resized.
    ViewNodeView constructor | TableView| A customNodeViewclass for rendering table nodes. Must follow theNodeViewinterface. Setting tonull` disables custom node views.
  6. Table editing commands

    master

    The following commands provide programmatic control over table structure and cell properties. Most commands follow the signature (state: EditorState, dispatch: ?fn(tr: Transaction)) → bool.

    Row and Column Manipulation

    • addColumnBefore(state, dispatch): Adds a column before the current selection.
    • addColumnAfter(state, dispatch): Adds a column after the current selection.
    • deleteColumn(state, dispatch): Removes selected columns.
    • addRowBefore(state, dispatch): Adds a row before the current selection.
    • addRowAfter(state, dispatch): Adds a row after the current selection.
    • deleteRow(state, dispatch): Removes selected rows.
    • deleteTable(state, dispatch): Deletes the table containing the selection.
    • moveTableRow(options: MoveTableRowOptions): Moves a row to a new index.
    • moveTableColumn(options: MoveTableColumnOptions): Moves a column to a new index.

    Cell Manipulation

    • mergeCells(state, dispatch): Merges selected cells into one (only works if selection is a rectangle).
    • splitCell(state, dispatch): Splits a cell with rowspan or colspan > 1 into smaller cells.
    • splitCellWithType(getType: fn) : Splits a cell using a custom NodeType returned by getType.
    • setCellAttr(name: string, value: any): Returns a command to set a specific attribute on the selected cell.
    • toggleHeaderRow(state, dispatch): Toggles header status for the selected row.
    • toggleHeaderColumn(state, dispatch): Toggles header status for the selected column.
    • toggleHeaderCell(state, dispatch): Toggles header status for the selected cells.
    • toggleHeader(type: string, options: ?{useDeprecatedLogic: bool}): Toggles between row/column header and normal cells (applies to first row/column).
    • goToNextCell(direction: number): Returns a command to move selection to the next (1) or previous (-1) cell.

    Utilities

    • fixTables(state, oldState?): Returns a transaction that repairs malformed tables in the document.
    • findTable($pos: ResolvedPos): Finds the closest table containing the given position.
    • findCellRange($pos, anchorHit?, headHit?): Finds the anchor and head cells for a selection.
    • findCellPos(doc: Node, pos: number): Finds the ResolvedPos of a cell using a position as a hit point.
  7. Set cell attributes

    master

    The setCellAttr(name, value) command returns a command that sets a specific attribute on the selected cell(s).

    • If a CellSelection is active, it applies the attribute to all cells in the selection.
    • If a single cell is selected, it applies it to that cell.
    • The command returns false if the attribute is already set to the provided value.
    // Example: Set a custom attribute 'data-id' to '123' on selected cells
    dispatch(setCellAttr('data-id', '123')(state));
  8. Access the column resizing plugin state

    master

    You can access the current state of the resizing plugin (such as which handle is active or if a drag is in progress) using the columnResizingPluginKey.

    import { columnResizingPluginKey } from 'prosemirror-tables';
    
    // Inside a plugin or editor event
    const state = columnResizingPluginKey.getState(editorState);
    if (state) {
      console.log(state.activeHandle); // The position of the active handle
      console.log(state.dragging);    // The Dragging object or false
    }
  9. Select a cell with handleTripleClick

    master

    Use handleTripleClick to quickly select an entire cell when a user triple-clicks a position in the editor.

    Returns true if the position was inside a table cell and a CellSelection was dispatched, otherwise returns false.

    import { handleTripleClick } from 'prosemirror-tables';
    
    // In your view's click handler:
    const handled = handleTripleClick(view, pos);
  10. Delete cell selection content

    master

    The deleteCellSelection(state, dispatch) command clears the content of the selected cells without deleting the cells themselves. It replaces the content with empty cells (matching the base cell content).

    // Example: Clear content in selected cells
    dispatch(deleteCellSelection(state));
  11. Generate table node specs with `tableNodes()`

    master

    Use the tableNodes function to create a set of ProseMirror NodeSpec objects for table, table_row, table_cell, and table_header. These specs can be merged into your existing schema's node set.

    To use this, provide a TableNodesOptions object specifying the cellContent (the content allowed inside cells) and any custom cellAttributes you want to support.

    import { tableNodes } from 'prosemirror-tables';
    
    const myTableNodes = tableNodes({
      tableGroup: 'block',
      cellContent: 'inline*',
      cellAttributes: {
        // Example of adding a custom attribute to cells
        className: {
          default: '',
          getFromDOM: (dom) => dom.getAttribute('class'),
          setDOMAttr: (value, attrs) => { attrs.class = value as string; }
        }
      }
    });
    
    // Then add myTableNodes to your schema definition