Migrating to Bst-Table
Already using a React data grid? The concepts carry over — Bst-Table just splits them into a headless
engine (enable* behaviour) and a skin (show* chrome). This page maps the ideas that
every grid shares onto Bst-Table's API, so you can port a grid without a rewrite. The vocabulary
below is deliberately generic — it applies whatever you're coming from.
Concept map
| What your current grid gives you | In Bst-Table |
|---|---|
| Column definitions (a field + a header) | columns: BstTableColumn[] — accessorKey + id + header |
| A custom cell renderer per column | a built-in meta.type (17 of them), or columnDef.cell for anything custom |
| A stable row id / key getter | getRowId={(r) => r.id} — required for selection & editing |
| One big grid component with dozens of props | one skin component + per-instance enable* / show* flags |
| Sorting & column-filter state | enableSorting / enableColumnFilters (on by default) |
| A global quick-filter / search box | enableGlobalFilter + showSearch |
| A row-selection model (checkboxes) | enableRowSelection + showSelectionInfo |
| Range / cell selection + copy-paste | enableCellSelection + enableClipboard |
| Inline / row / bulk editing | enableEditing={{ mode }} (cell / row / batch) |
| Frozen / pinned columns & rows | enableColumnPinning / enableRowPinning |
| Master-detail / expandable rows | enableExpanding + renderDetail |
| Grouping with aggregates | enableGrouping (+ a column aggregationFn) |
| Column resize / reorder / show-hide | enableColumnResizing / enableColumnOrdering / enableHiding |
| Virtualized / windowed rows | enableVirtualization |
| Server-side (lazy) data operations | a DataSource in manual mode (useBstDataSource) |
| CSV / Excel / print export | enableExport + showExport |
| Theme tokens & dark mode | the MUI theme, or shadcn theme="inherit" |
Columns & cells
Instead of a bespoke renderer per column, pick a built-in cell type with meta.type and
configure it through cellMeta; drop to columnDef.cell only for something the built-ins don't
cover.
const columns: BstTableColumn<Row>[] = [
{ id: 'name', accessorKey: 'name', header: 'Name' },
{ id: 'status', accessorKey: 'status', header: 'Status',
meta: { type: 'singleSelect', options: STATUSES } },
{ id: 'trend', accessorKey: 'history', header: 'Trend',
meta: { type: 'sparkline' } },
]
See Cell Types for the full set.
Data operations
Sorting, filtering, search, grouping and pagination are engine features and mostly default on —
turn them off with enableSorting={false} etc., or reach for the advanced pieces (enableSetFilter,
enableMultiFilter) when you need them. See Data operations.
Selection, editing & clipboard
These default off — opt in per grid:
<BstTableMui
data={rows}
columns={columns}
getRowId={(r) => r.id}
enableRowSelection
enableCellSelection
enableClipboard
enableEditing={{ mode: 'batch' }}
onSave={async ({ rows }) => api.bulkUpdate(rows.map((r) => r.patch))}
/>
Details in Editing and Selection & clipboard.
Large / server-side data
For big tables, run sort / filter / paginate on the server behind a DataSource in manual mode and turn on virtualization — the grid API stays the same, only the data source changes. See Performance.
Styling
Map your existing look with Styling & Theming: the MUI skin follows your MUI theme,
the shadcn skin adopts your design tokens via theme="inherit", and the CSS slots
(classNames / styles) cover the rest.
Port it in five steps
- Columns — translate your column list to
BstTableColumn[](accessorKey+header) and pick ameta.typeper column. - Row id — add
getRowIdso selection and editing target rows by id, not index. - Turn on what you need — flip the
enable*/show*flags for the features your old grid had (use the concept map above). - Wire data changes —
onDataChangefor inline edits, or a singleonSavefor a batched write. - Theme — match your app with the MUI theme or shadcn tokens.
Why the switch is worth it
Master-detail, range selection, clipboard and export ship under MIT / Apache — no per-seat licensing and no paid tiers gating features. You build on the headless engine you already control.
If you use an AI coding assistant, connect the MCP server first — it can scaffold the equivalent Bst-Table grid and validate the config for you.