Cell Plugins
Define a table property's data semantics and its matching UI adapter.
A custom property is registered as a matched pair: a pure
CellPlugin<Key, Data, Config> from @notion-kit/table-hook and a
TableUiPlugin from @notion-kit/table-view. Both use the same property type
ID.
Data plugin definition
| Field | Description |
|---|---|
id | Unique property type identifier. |
default | Default cell data and property configuration. |
fromValue | Converts a comparable value into cell data. |
toValue | Converts cell data for sorting and grouping. |
toGroupValue | Optionally converts cell data to a grouping value; falls back to toValue. |
isEmpty | Defines empty data for filters, counts, sorting, and grouping. |
toTextValue | Converts cell data to copyable text. |
sorting, grouping, counting, filtering | Optional pure data capabilities discovered by table menus. |
compare | Legacy row comparator used as a sorting fallback when no registered sorting method resolves. |
transferConfig | Optionally derives configuration when a property changes to this type, using its existing rows. |
Data plugins do not render React, carry icons, or decide cell presentation.
UI adapter definition
| Field | Description |
|---|---|
id | Must match the data plugin ID. |
meta | Type-menu name, description, and icon. |
default | Default property name, icon, and optional width. |
renderCell | Required. Returns the complete React UI for a cell surface. |
renderReadOnlyValue | Optional historical value renderer. Receives snapshots without a live cell or mutation callbacks. |
renderBulkEditor | Optional. Its presence enables bulk editing. |
renderConfigMenu | Optional property configuration UI. |
renderGroupingValue | Required. Returns the grouped label UI. |
renderCell receives CellProps, containing only a TanStack cell instance.
Use cell.getInfo(), cell.getPlugin(), cell.getData(),
cell.getTextValue(), and cell.update() to read and change the cell.
renderBulkEditor and renderConfigMenu receive BulkEditorProps and
ConfigMenuProps, each containing only a TanStack column instance. The
column exposes getInfo(), getPlugin(), getSelectedRowIds(), getCell(),
updateCells(), and updateConfig(). Adapters own their triggers, popovers,
empty states, copy affordances, and layout classes.
Read-only history renderers
renderReadOnlyValue is optional. Existing adapters remain compatible and use
the record's textValue when the renderer is absent. The renderer receives
ReadOnlyValueProps:
| Field | Description |
|---|---|
value | Historical cell value, typed as unknown. |
config | Historical property configuration, typed as unknown. |
property | Historical ID, name, icon, type, and optional configuration. |
textValue | Historical plain-text representation used for fallback. |
Validate the snapshot with Zod before rendering it. Return textValue when the
value or configuration is unsupported. Return Empty for an empty value;
keep false checkboxes and numeric zero visible. A text adapter can provide:
import { z } from "zod";
import type { ReadOnlyValueProps } from "@notion-kit/table-view";
function HistoricalText({ value, textValue }: ReadOnlyValueProps) {
const result = z.string().safeParse(value);
if (!result.success) return textValue;
return (
<span className="wrap-anywhere whitespace-pre-wrap">
{result.data || "Empty"}
</span>
);
}
// In the UI adapter:
// renderReadOnlyValue: (props) => <HistoricalText {...props} />A renderer receives no table, cell, editor, or mutation callback. It uses only the stored metadata, even after the current property or an option is renamed, reconfigured, or removed. Keep it read-only and reuse your value component without mounting its editor. Built-in adapters follow this contract for text, tags, checkboxes, numbers, links, dates, and resolved timestamps.
Unknown property types use textValue. A rendering error is isolated to the
individual value and also shows textValue; other records remain visible.
Registration
const plugins = {
data: [tagPlugin],
ui: [tagPluginUi],
};
<TableView plugins={plugins} />;The registry rejects missing, duplicate, and unmatched IDs. There is no combined-plugin registration path.
Types
| Type | Description |
|---|---|
CellPlugin<Key, Data, Config> | Pure table-hook data semantics and capabilities. |
TableUiPlugin<TPlugin> | React adapter coupled to one data plugin. |
CellProps | A TanStack cell instance for direct rendering. |
BulkEditorProps | A TanStack column instance for bulk rendering. |
ReadOnlyValueProps | Historical value, config, property metadata, and fallback text. |
ConfigMenuProps | A TanStack column instance for configuration UI. |
Calendar title cards use the calendar cell surface. Custom title adapters can
render a compact label for this surface, as they do for timeline; the Calendar
event owns opening, dragging, and resizing.