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

FieldDescription
idUnique property type identifier.
defaultDefault cell data and property configuration.
fromValueConverts a comparable value into cell data.
toValueConverts cell data for sorting and grouping.
toGroupValueOptionally converts cell data to a grouping value; falls back to toValue.
isEmptyDefines empty data for filters, counts, sorting, and grouping.
toTextValueConverts cell data to copyable text.
sorting, grouping, counting, filteringOptional pure data capabilities discovered by table menus.
compareLegacy row comparator used as a sorting fallback when no registered sorting method resolves.
transferConfigOptionally 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

FieldDescription
idMust match the data plugin ID.
metaType-menu name, description, and icon.
defaultDefault property name, icon, and optional width.
renderCellRequired. Returns the complete React UI for a cell surface.
renderReadOnlyValueOptional historical value renderer. Receives snapshots without a live cell or mutation callbacks.
renderBulkEditorOptional. Its presence enables bulk editing.
renderConfigMenuOptional property configuration UI.
renderGroupingValueRequired. 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:

FieldDescription
valueHistorical cell value, typed as unknown.
configHistorical property configuration, typed as unknown.
propertyHistorical ID, name, icon, type, and optional configuration.
textValueHistorical 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

TypeDescription
CellPlugin<Key, Data, Config>Pure table-hook data semantics and capabilities.
TableUiPlugin<TPlugin>React adapter coupled to one data plugin.
CellPropsA TanStack cell instance for direct rendering.
BulkEditorPropsA TanStack column instance for bulk rendering.
ReadOnlyValuePropsHistorical value, config, property metadata, and fallback text.
ConfigMenuPropsA 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.