Add a Feature Across Framework Adapters
When adding a new grid feature that needs framework adapter support (Angular, React, Vue), follow this guide to ensure consistency and feature parity.
Architecture Overview
| Library | Path | Pattern |
|---|---|---|
@toolbox-web/grid-angular |
libs/grid-angular/ |
Angular directives + AngularGridAdapter |
@toolbox-web/grid-react |
libs/grid-react/ |
React components + ReactGridAdapter |
@toolbox-web/grid-vue |
libs/grid-vue/ |
Vue composables + VueGridAdapter |
All adapters register a framework-specific GridAdapter that handles rendering cells/editors/panels using the framework's template system.
Step 1: Understand the Core Feature
Before touching adapters, understand how the feature works in the vanilla grid:
- Read the relevant core code in
libs/grid/src/lib/ - Check if the feature uses:
- Custom renderers (cell, header, filter) → Adapters need to wrap framework components
- Events → Adapters need to expose framework-idiomatic event binding
- Configuration → Adapters may extend config types
- DOM manipulation → Adapters might need lifecycle management
Step 2: Angular Adapter (libs/grid-angular/)
Exported API
Griddirective — Auto-registersAngularGridAdapteron<tbw-grid>elementsTbwRenderer— Structural directive (*tbwRenderer) for cell renderer templatesTbwEditor— Structural directive (*tbwEditor) for cell editor templates with auto-wired commit/cancelGridColumnView/GridColumnEditor— Alternative nested element syntax with<ng-template>
Usage Example
import { Component } from '@angular/core';
import { Grid, TbwRenderer, TbwEditor } from '@toolbox-web/grid-angular';
@Component({
imports: [Grid, TbwRenderer, TbwEditor],
template: `
<tbw-grid [rows]="data" [gridConfig]="config">
<tbw-grid-column field="status">
<app-status-badge *tbwRenderer="let value; row as row" [value]="value" [row]="row" />
<app-status-select *tbwEditor="let value" [value]="value" />
</tbw-grid-column>
</tbw-grid>
`
})
export class GridComponent { ... }
Key Files
src/lib/grid.directive.ts— MainGriddirective (auto-registers adapter)src/lib/angular-grid-adapter.ts— Adapter that renders Angular templatessrc/lib/directives/— Structural directives (TbwRenderer,TbwEditor, etc.)src/index.ts— Public exports
Pattern
- Use structural directives (
*tbwXxx) for template-driven features - Use
@Input()/@Output()for configuration - Register new template types in the adapter's
renderCell/renderEditormethods - Export from
src/index.ts
Testing
- Co-located
*.spec.tsfiles - Use
Object.create(Class.prototype)for testing class methods without DI - Run:
bun nx test grid-angular
Step 3: React Adapter (libs/grid-react/)
Exported API
Components: DataGrid, GridColumn, GridDetailPanel, GridToolPanel, GridToolButtons
Hooks: useGrid (programmatic access), useGridEvent (type-safe event subscription)
Types: ReactGridConfig (extends GridConfig with React renderers), ReactColumnConfig
Usage Example
import { DataGrid, type ReactGridConfig } from '@toolbox-web/grid-react';
import { SelectionPlugin } from '@toolbox-web/grid/all';
const config: ReactGridConfig<Employee> = {
columns: [
{ field: 'name', header: 'Name' },
{
field: 'status',
renderer: (ctx) => <StatusBadge value={ctx.value} />,
editor: (ctx) => <StatusSelect value={ctx.value} />,
},
],
plugins: [new SelectionPlugin({ mode: 'row' })],
};
function App() {
return <DataGrid rows={employees} gridConfig={config} />;
}
Key Files
src/lib/DataGrid.tsx— MainDataGridcomponentsrc/lib/react-grid-adapter.ts— Adapter that renders React elementssrc/lib/GridColumn.tsx— Declarative column with render propssrc/lib/hooks/—useGrid,useGridEventsrc/index.ts— Public exports
Pattern
- Use render props or React component types in config
- Extend
ReactGridConfig/ReactColumnConfigfor new renderable slots - Add hooks for new event subscriptions if needed
- Export from
src/index.ts
Testing
- Use
@testing-library/reactwithrender() - Mock grid element for hook tests
- Run:
bun nx test grid-react
Step 4: Vue Adapter (libs/grid-vue/)
Exported API
Components: DataGrid, GridColumn, GridDetailPanel, GridToolPanel, GridToolButtons
Composables: useGrid (programmatic access), useGridEvent (event subscription)
Types: VueGridConfig (extends GridConfig with Vue slot renderers), VueColumnConfig
Usage Example
<script setup lang="ts">
import { DataGrid, GridColumn } from '@toolbox-web/grid-vue';
import { SelectionPlugin } from '@toolbox-web/grid/all';
import StatusBadge from './StatusBadge.vue';
const config = {
plugins: [new SelectionPlugin({ mode: 'row' })],
};
</script>
<template>
<DataGrid :rows="employees" :gridConfig="config">
<GridColumn field="status" header="Status">
<template #renderer="{ value, row }">
<StatusBadge :value="value" :row="row" />
</template>
</GridColumn>
</DataGrid>
</template>
Key Files
src/lib/DataGrid.vue— MainDataGridcomponentsrc/lib/vue-grid-adapter.ts— Adapter that renders Vue slotssrc/lib/composables.ts—useGrid,useGridEventsrc/lib/registry files— WeakMap-based registries for panels, cards, etc.src/index.ts— Public exports
Pattern
- Use slots and registry pattern (WeakMap keyed on grid element) for renderables
- Add composables for new grid interactions
- Extend
VueGridConfig/VueColumnConfigfor new features - Export from
src/index.ts
Testing
- Use
@vue/test-utilswithmount() - Test composables via
defineComponentwrappers - Run:
bun nx test grid-vue
Step 5: Verify Feature Parity
After implementing across all adapters:
- Types align: Config extensions should have equivalent properties
- Behavior matches: Same user interactions produce same results
- Tests cover: Each adapter has tests for the new feature
- Docs updated: README files and any MDX docs reflect new feature
- Exports added: New public types/components exported from barrel files
Step 6: Run All Tests
bun run test
Ensure all 4 projects pass (grid, grid-angular, grid-react, grid-vue).
Checklist
- Core grid feature working in vanilla mode
- Angular adapter updated with directive/template support
- React adapter updated with component/hook support
- Vue adapter updated with composable/slot support
- Tests added for each adapter
- Public exports updated in each
index.ts - TypeScript types consistent across adapters
- All tests passing
Converted and distributed by TomeVault — claim your Tome and manage your conversions.