Skip to content

Table

The table layer (@blocknote/block-view/table) provides a framework-agnostic abstraction over the data model. It converts collections and views into rows, columns, and cells suitable for rendering.

Factory function that creates a CollectionTable instance.

import { createCollectionTable } from "@blocknote/block-view/table";
const table = createCollectionTable({
collectionManager: manager,
viewId: "view-1",
getCellRenderer: (property) => renderers[property.type],
propertyDefinitions: defaultPropertyDefinitions,
});
type CreateCollectionTableParams = {
collectionManager: CollectionManager;
viewId: string;
getCellRenderer: (property: Property) => CellRenderer;
propertyDefinitions: PropertyDefinition<any>[];
getEditable?: (document: Document, property: Property) => boolean;
};
ParamDescription
collectionManagerThe initialized collection manager
viewIdWhich view to render
getCellRendererReturns a cell renderer component for a given property
propertyDefinitionsAll property definitions (built-in + custom)
getEditableOptional per-cell editability check

In practice, you’ll use useCollectionTableView (React) instead of calling this directly. The hook handles renderer resolution and subscription setup for you.

The core table instance. Provides rows, columns, selection, and subscription APIs.

import type { CollectionTable } from "@blocknote/block-view/table";
table.rows: TableRow[]
table.columns: TableColumn[]
table.getIsAllRowsSelected(): boolean
table.getIsSomeRowsSelected(): boolean
table.getToggleAllRowsSelectedHandler(): () => void
table.getSelectedRowsById(): Record<string, TableRow>
table.resetRowSelection(): void

The table uses useSyncExternalStore-compatible subscription APIs. Three separate channels minimize unnecessary re-renders:

// Subscribe to row data changes
table.subscribe(listener: () => void): () => void
table.getSnapshot(): number
// Subscribe to column changes (resize, reorder, add, remove)
table.subscribeToColumns(listener: () => void): () => void
table.getColumnsRevision(): number
// Subscribe to selection changes
table.subscribeToSelection(listener: () => void): () => void
table.getSelectionSnapshot(): RowSelectionState
table.refresh(): void // Rebuild rows/columns from current model state
table.setEditable(value: boolean): void
table.connect(): () => void // Start listening to model changes; returns disconnect function
table.transaction: Transaction
table.view: CollectionView
table.collectionManager: CollectionManager
table.undoRedoManager: UndoRedoManager
table.propertyDefinitions: PropertyDefinition<any>[]
table.getPendingAutoFocus(): { documentId: string; propertyId: string } | null
table.setPendingAutoFocus(target: { documentId: string; propertyId: string } | null): void

Used internally to focus a cell after creating a new document.

interface TableRow {
id: string; // document ID
index: number; // row index
original: Document; // the underlying Document entity
cells: TableCell[]; // cells in this row
getIsSelected(): boolean;
toggleSelected(): void;
}
for (const row of table.rows) {
console.log(row.id, row.original.getProp("name")?.value);
console.log("Selected:", row.getIsSelected());
}
interface TableColumn {
id: string; // property ID or special column ID
size: number; // width in pixels
property?: Property; // the underlying Property (undefined for utility columns like selection)
cell?: (context: CellContext) => ReactNode; // cell renderer
}
interface TableCell {
id: string; // unique cell ID
column: TableColumn;
row: TableRow;
render(): ReactNode; // renders the cell content
}

Passed to column cell renderers:

interface CellContext {
getValue(): PropertyValue | undefined;
row: TableRow;
column: TableColumn;
table: CollectionTable;
}

The interface for cell renderer components:

interface CellRendererParams {
value: PropertyValue | undefined;
property: Property;
document: Document;
table: CollectionTable;
editable?: boolean;
onChange: (changes: { value: string; ref?: { type: string; id: string } }) => void;
autoFocus?: boolean;
}
type CellRenderer = FC<CellRendererParams>;
const MyCellRenderer: CellRenderer = ({ value, editable, onChange, autoFocus }) => {
const displayValue = value?.value ?? "";
if (!editable) {
return <span>{displayValue}</span>;
}
return (
<input
value={displayValue}
autoFocus={autoFocus}
onChange={(e) => onChange({ value: e.target.value })}
/>
);
};
type RowSelectionState = Record<string, boolean>;
// Keys are document IDs, values are selection state

Utility functions for creating columns from view configuration:

import {
createColumn,
getColumnsFromView,
COLUMN_DRAG_DATA_KEY,
getColumnDragData,
} from "@blocknote/block-view/table";
function createColumn(options: CreateColumnOptions): TableColumn;
function getColumnsFromView(options: GetColumnsFromViewOptions): TableColumn[];

Converts a view’s column configuration into TableColumn[] objects, resolving property definitions and cell renderers.

const COLUMN_DRAG_DATA_KEY: string;
type ColumnDragData = {
/* column drag metadata */
};
function getColumnDragData(data: Record<string, unknown>): ColumnDragData | undefined;

Used by the built-in column reordering feature with @atlaskit/pragmatic-drag-and-drop.