Migrating from v2 to v3
This guide covers the breaking changes in @toolbox-web/grid v3. Every removed
symbol was @deprecated throughout the v2.x line, so if you kept up with IDE
deprecation warnings you may have little to change.
The main focus of this version was to improve core isolation from plugins/features to improve bundle size on both core and adapters. The adapter that benefitted most from this was the grid-angular package which halved its bundle size.
The shell is now opt-in
Section titled “The shell is now opt-in”The biggest behavioural change: the shell (header bar, toolbar content, and
tool panels) was extracted into a built-in ShellPlugin and is no longer
auto-registered. A bare <tbw-grid> now renders no shell chrome, which lets
the shell tree-shake out of the core bundle when you don’t use it.
Activate the shell explicitly using one of these forms:
// Side-effect import registers the feature, then enable it in gridConfig.import '@toolbox-web/grid/features/shell';
grid.gridConfig = { features: { shell: true }, // or: { shell: { /* ShellConfig */ } }};import { ShellPlugin } from '@toolbox-web/grid/plugins/shell';
grid.gridConfig = { plugins: [new ShellPlugin(/* ShellConfig */)],};Shell API access
Section titled “Shell API access”The deprecated grid-element shell delegates (grid.openToolPanel(...),
grid.registerHeaderContent(...), grid.getToolPanels(), etc.) have been
removed. Reach the shell through the plugin instance instead:
const shell = grid.getPluginByName('shell');shell?.openToolPanel('filters');shell?.registerHeaderContent(/* ... */);Shell config types
Section titled “Shell config types”The shell config types are no longer re-exported from the core entry point. Import them from the plugin subpath:
// v2 (removed core re-exports)// import type { ShellConfig, ToolPanelConfig } from '@toolbox-web/grid';
// v3import type { ShellConfig, ToolPanelConfig } from '@toolbox-web/grid/plugins/shell';Removed deprecated API
Section titled “Removed deprecated API”| v2 (removed) | v3 (replacement) |
|---|---|
DGEvents, DGEventName | String literals typed against DataGridEventMap (or keyof DataGridEventMap) |
PluginEvents, PluginEventName | String literals typed against DataGridEventMap |
@toolbox-web/grid/plugins/reorder-rows (RowReorderPlugin) | @toolbox-web/grid/plugins/row-drag-drop (RowDragDropPlugin) |
RowDragDropConfig.canDragRow | RowDragDropConfig.canDrag |
RowDragDropConfig.canMove | RowDragDropConfig.canDrag(row, index) — no direct 1:1; the old (row, from, to, direction) signature is gone (veto now runs on drag start) |
ServerSideConfig.cacheBlockSize | ServerSideConfig.pageSize |
ServerSidePlugin.getNodeCount() | ServerSidePlugin.getTotalNodeCount() |
ServerSidePlugin.isLoaded(index) | ServerSidePlugin.isNodeLoaded(index) |
PinnedRowsConfig.position, showRowCount, showSelectedCount, showFilteredCount, aggregationRows, customPanels | PinnedRowsConfig.slots[] |
PinnedRowsPlugin.addPanel / removePanel / addAggregationRow / removeAggregationRow | Configure slots[] declaratively |
Event listeners
Section titled “Event listeners”// v2 (removed)import { DGEvents, PluginEvents } from '@toolbox-web/grid';grid.on(DGEvents.SORT_CHANGE, (detail) => { /* ... */ });grid.on(PluginEvents.FILTER_CHANGE, (detail) => { /* ... */ });
// v3 — string literals are type-checked against DataGridEventMapgrid.on('sort-change', (detail) => { /* ... */ });grid.on('filter-change', (detail) => { /* ... */ });Pinned rows
Section titled “Pinned rows”// v2 (removed legacy fields)new PinnedRowsPlugin({ showRowCount: true, aggregationRows: [/* ... */] });
// v3 — the unified slots[] APInew PinnedRowsPlugin({ slots: [ { position: 'bottom', aggregators: { price: 'sum' }, label: 'Total' }, ],});The default new PinnedRowsPlugin() still seeds the familiar bottom info bar
(row count, filtered count, selected count), so the no-argument case is unchanged.
Angular adapter (@toolbox-web/grid-angular)
Section titled “Angular adapter (@toolbox-web/grid-angular)”The Angular adapter’s v2 major ships alongside grid core v3 and applies the
same core-isolation principle: feature directives, editor/filter base classes,
and inject helpers moved out of the package’s main entry into per-feature
subpaths (@toolbox-web/grid-angular/features/*). This is what roughly halves
the adapter’s baseline bundle — the main entry now pulls in only the core Grid
directive plus shared types, and every feature tree-shakes away unless you import
its subpath.
The main entry (@toolbox-web/grid-angular) still exports the core surface:
Grid, TbwGridColumn, TbwGridHeader, TbwGridToolButtons, TbwRenderer,
GridColumnView, injectGrid, provideGrid / provideGridIcons /
provideGridTypeDefaults, and the shared types (GridConfig, ColumnConfig,
CellEditor, CellRenderer, FilterPanel, CellCommitEvent, RowCommitEvent).
Everything feature-specific moved. Most apps hit three mechanical changes.
1. Import base classes & inject helpers from their feature subpath
Section titled “1. Import base classes & inject helpers from their feature subpath”| v2 symbol(s) | Import from |
|---|---|
BaseGridEditor, BaseGridEditorCVA, BaseOverlayEditor, TbwEditor, GridFormArray, GridColumnEditor, GridLazyForm | @toolbox-web/grid-angular/features/editing |
BaseFilterPanel, injectGridFiltering, FilterConfig | @toolbox-web/grid-angular/features/filtering |
injectGridSelection | @toolbox-web/grid-angular/features/selection |
GridToolPanel, GridHeaderContent, GridToolbarContent | @toolbox-web/grid-angular/features/shell |
// v1import { BaseGridEditor, BaseOverlayEditor, TbwEditor, GridToolPanel } from '@toolbox-web/grid-angular';
// v2import { BaseGridEditor, BaseOverlayEditor, TbwEditor } from '@toolbox-web/grid-angular/features/editing';import { GridToolPanel } from '@toolbox-web/grid-angular/features/shell';2. Import a feature directive for every feature you bind in a template
Section titled “2. Import a feature directive for every feature you bind in a template”In v1 the core Grid directive silently owned the feature inputs
([filtering], [editing], [selection], …). In v2 each binding is owned by its
own directive in the feature subpath. If your <tbw-grid> template binds a
feature, add that directive to the standalone component’s imports (importing it
also registers the vanilla bridge as a side effect). Forget it and Angular fails
the build with NG8002: Can't bind to 'filtering' since it isn't a known property of 'tbw-grid'.
import { Grid } from '@toolbox-web/grid-angular';import { GridFilteringDirective } from '@toolbox-web/grid-angular/features/filtering';import { GridEditingDirective } from '@toolbox-web/grid-angular/features/editing';
@Component({ imports: [Grid, GridFilteringDirective, GridEditingDirective /* … */], template: `<tbw-grid [filtering]="true" [editing]="editConfig" />`,})export class MyComponent {}Binding → directive → subpath (each subpath also exports the directive):
| Template binding | Directive | Subpath |
|---|---|---|
[filtering], (filterChange) | GridFilteringDirective | features/filtering |
[editing], (cellCommit), (rowCommit), (cellCancel), … | GridEditingDirective | features/editing |
[selection], (selectionChange) | GridSelectionDirective | features/selection |
[contextMenu], (contextMenuOpen) | GridContextMenuDirective | features/context-menu |
[visibility] | GridVisibilityDirective | features/visibility |
[rowDragDrop], (rowMove), (rowDrop), … | GridRowDragDropDirective | features/row-drag-drop |
[tree], (treeExpand) | GridTreeDirective | features/tree |
[masterDetail], (detailExpand) | GridMasterDetailDirective | features/master-detail |
[multiSort] | GridMultiSortDirective | features/multi-sort |
[pinnedRows] | GridPinnedRowsDirective | features/pinned-rows |
[pinnedColumns] | GridPinnedColumnsDirective | features/pinned-columns |
[groupingRows], (groupToggle), (groupExpand), … | GridGroupingRowsDirective | features/grouping-rows |
[groupingColumns] | GridGroupingColumnsDirective | features/grouping-columns |
[reorderColumns], (columnMove) | GridReorderColumnsDirective | features/reorder-columns |
[clipboard], (copy), (paste) | GridClipboardDirective | features/clipboard |
[export], (exportComplete) | GridExportDirective | features/export |
[print], (printStart), (printComplete) | GridPrintDirective | features/print |
[responsive], (responsiveChange) | GridResponsiveDirective | features/responsive |
[stickyRows] | GridStickyRowsDirective | features/sticky-rows |
[serverSide] | GridServerSideDirective | features/server-side |
[pivot] | GridPivotDirective | features/pivot |
[tooltip] | GridTooltipDirective | features/tooltip |
[undoRedo], (undo), (redo) | GridUndoRedoDirective | features/undo-redo |
[columnVirtualization] | GridColumnVirtualizationDirective | features/column-virtualization |
Prefer configuring a feature in gridConfig (features / plugins) over a
template binding when you don’t need the two-way input — then no directive import
is required at all.
3. reorder-rows → row-drag-drop, and shell delegates
Section titled “3. reorder-rows → row-drag-drop, and shell delegates”Mirroring the core rename (RowReorderPlugin → RowDragDropPlugin), the Angular
subpath and its template binding were renamed:
import '@toolbox-web/grid-angular/features/reorder-rows';import { GridRowDragDropDirective } from '@toolbox-web/grid-angular/features/row-drag-drop';
<tbw-grid [reorderRows]="true" /><tbw-grid [rowDragDrop]="true" />The removed shell element-delegates (see Shell API access) apply to Angular too — reach the shell through the plugin instead of the element:
this.grid.element()?.toggleToolPanel();this.grid.element()?.getPluginByName('shell')?.toggleToolPanel();4. Enable the shell for features that render in a tool panel
Section titled “4. Enable the shell for features that render in a tool panel”The shell being opt-in is the change most likely to
bite an Angular grid at runtime (not build time), because v1 auto-registered
it. Any feature that renders into a tool panel — most commonly visibility (its
column list) — declares a hard dependency on the shell and throws
TBW020 if the shell is absent.
There is no [shell] template directive (the shell subpath only exports the
content directives GridToolPanel, GridHeaderContent, GridToolbarContent).
Enable the shell through gridConfig, and register its feature with the usual
side-effect import:
import '@toolbox-web/grid-angular/features/shell';features: { shell: true, visibility: true, // …},This holds even when the dependent feature is enabled through a template
directive (<tbw-grid [visibility]="true">): the directive contributes the
visibility feature, but the shell still has to come from gridConfig.features.
React (@toolbox-web/grid-react) & Vue (@toolbox-web/grid-vue)
Section titled “React (@toolbox-web/grid-react) & Vue (@toolbox-web/grid-vue)”Like Angular, the React and Vue adapters ship a v2 major alongside grid core
v3 and now require @toolbox-web/grid@^3.0.0 as a peer dependency. Their changes
are identical, so the steps below apply to both — substitute <DataGrid …>
(React) or <TbwGrid …> (Vue) as appropriate.
1. reorderRows prop → rowDragDrop
Section titled “1. reorderRows prop → rowDragDrop”Mirroring the core rename, the reorderRows prop and its features/reorder-rows
subpath were removed. Use rowDragDrop and the features/row-drag-drop subpath:
import '@toolbox-web/grid-react/features/reorder-rows';import '@toolbox-web/grid-react/features/row-drag-drop';
<DataGrid reorderRows /><DataGrid rowDragDrop />2. Pinned-rows customPanels → slots[]
Section titled “2. Pinned-rows customPanels → slots[]”The adapter-specific pinnedRows.customPanels array (which accepted a
framework-component render function) was removed in favour of the unified
slots[] API, matching the core pinned-rows change. Move each
custom panel into a slots[] entry:
pinnedRows={{ customPanels: [{ id: 'total', position: 'bottom', render: () => <Total /> }], slots: [{ position: 'bottom', render: () => <Total /> }],}}3. SSRProps / ssr prop removed
Section titled “3. SSRProps / ssr prop removed”The deprecated ssr prop and the exported SSRProps type were removed from
both adapters. The prop was a no-op — features register via SSR-safe side-effect
imports, and <tbw-grid> is a custom element that hydrates normally on the
client regardless of the flag. Delete any ssr prop and SSRProps import;
no replacement is needed.
import type { SSRProps } from '@toolbox-web/grid-react';<DataGrid ssr rows={rows} columns={columns} /><DataGrid rows={rows} columns={columns} />If you need real server-side rendering (Next.js / Remix / Nuxt / Vike / Astro), open an issue describing your hydration requirements.
4. Shell is opt-in here too
Section titled “4. Shell is opt-in here too”The shell being opt-in applies to React and Vue as
well. Enable it with the shell prop (or via gridConfig.features.shell), and
reach the shell instance through the grid element ref rather than removed
element delegates — see Shell API access. Features that
render into a tool panel (e.g. visibility) throw
TBW020 at runtime when the shell is absent.
<DataGrid visibility /><DataGrid shell visibility />