Package Exports
- @toolbox-web/grid-react
- @toolbox-web/grid-react/package.json
Readme
@toolbox-web/grid-react
React adapter for @toolbox-web/grid data grid component. Provides components and hooks for declarative React integration with custom cell renderers and editors.
Features
- ✅ Full React integration - Use JSX for cell renderers and editors
- ✅ Declarative columns - Define columns via props or
GridColumncomponents - ✅ Render props - Clean
childrensyntax for custom cells - ✅ Type-level defaults - App-wide renderers/editors via
GridTypeProvider - ✅ Hooks API -
useGridanduseGridEventfor programmatic access - ✅ Ref forwarding - Access grid instance via
DataGridRef - ✅ Master-detail -
GridDetailPanelfor expandable rows - ✅ Tool panels -
GridToolPanelfor custom sidebar content - ✅ Full type safety - TypeScript generics support
- ✅ React 18+ - Concurrent features and Suspense compatible
Installation
# npm
npm install @toolbox-web/grid @toolbox-web/grid-react
# yarn
yarn add @toolbox-web/grid @toolbox-web/grid-react
# pnpm
pnpm add @toolbox-web/grid @toolbox-web/grid-react
# bun
bun add @toolbox-web/grid @toolbox-web/grid-reactQuick Start
1. Register the Grid Component
In your application entry point, import the grid registration:
// main.tsx or index.tsx
import '@toolbox-web/grid';2. Use in Components
import { DataGrid } from '@toolbox-web/grid-react';
interface Employee {
id: number;
name: string;
department: string;
salary: number;
}
function EmployeeGrid() {
const [employees, setEmployees] = useState<Employee[]>([
{ id: 1, name: 'Alice', department: 'Engineering', salary: 95000 },
{ id: 2, name: 'Bob', department: 'Marketing', salary: 75000 },
{ id: 3, name: 'Charlie', department: 'Sales', salary: 85000 },
]);
return (
<DataGrid
rows={employees}
columns={[
{ field: 'id', header: 'ID', width: 60 },
{ field: 'name', header: 'Name', sortable: true },
{ field: 'department', header: 'Department', sortable: true },
{ field: 'salary', header: 'Salary', type: 'number' },
]}
onRowsChange={setEmployees}
/>
);
}Custom Cell Renderers
There are two ways to define custom renderers: inline in the configuration, or via GridColumn components.
Inline Configuration (Recommended)
Define renderers directly in your ReactGridConfig:
import { DataGrid, type ReactGridConfig } from '@toolbox-web/grid-react';
const config: ReactGridConfig<Employee> = {
columns: [
{ field: 'name', header: 'Name' },
{
field: 'status',
header: 'Status',
// Custom React renderer - same property name as vanilla!
renderer: (ctx) => <span className={`badge badge-${ctx.value.toLowerCase()}`}>{ctx.value}</span>,
},
],
};
function EmployeeGrid() {
return <DataGrid rows={employees} gridConfig={config} />;
}Renderer Context:
| Property | Type | Description |
|---|---|---|
value |
TValue |
The cell value |
row |
TRow |
The full row data object |
column |
unknown |
The column configuration |
Using GridColumn Components
Use the GridColumn component with a render prop:
import { DataGrid, GridColumn } from '@toolbox-web/grid-react';
function StatusBadge({ status }: { status: string }) {
return <span className={`badge badge-${status.toLowerCase()}`}>{status}</span>;
}
function EmployeeGrid() {
return (
<DataGrid rows={employees}>
<GridColumn field="name" header="Name" />
<GridColumn field="status">{(ctx) => <StatusBadge status={ctx.value} />}</GridColumn>
</DataGrid>
);
}Custom Cell Editors
Define editors inline in your configuration or via GridColumn:
Inline Configuration
const config: ReactGridConfig<Employee> = {
columns: [
{
field: 'status',
header: 'Status',
editable: true,
renderer: (ctx) => <StatusBadge status={ctx.value} />,
editor: (ctx) => (
<select
defaultValue={ctx.value}
autoFocus
onChange={(e) => ctx.commit(e.target.value)}
onKeyDown={(e) => e.key === 'Escape' && ctx.cancel()}
>
<option value="active">Active</option>
<option value="inactive">Inactive</option>
</select>
),
},
],
};Editor Context:
| Property | Type | Description |
|---|---|---|
value |
TValue |
The current cell value |
row |
TRow |
The full row data object |
column |
unknown |
The column configuration |
commit |
(v) => void |
Callback to commit new value |
cancel |
() => void |
Callback to cancel editing |
Using GridColumn
<DataGrid rows={employees}>
<GridColumn
field="name"
editable
editor={(ctx) => (
<input
autoFocus
defaultValue={ctx.value}
onBlur={(e) => ctx.commit(e.target.value)}
onKeyDown={(e) => {
if (e.key === 'Enter') ctx.commit(e.currentTarget.value);
if (e.key === 'Escape') ctx.cancel();
}}
/>
)}
/>
</DataGrid>Master-Detail with GridDetailPanel
Create expandable row details using the GridDetailPanel component:
import { DataGrid, GridDetailPanel } from '@toolbox-web/grid-react';
import { MasterDetailPlugin } from '@toolbox-web/grid/all';
function EmployeeGrid() {
const config: ReactGridConfig<Employee> = {
columns: [...],
plugins: [new MasterDetailPlugin()],
};
return (
<DataGrid rows={employees} gridConfig={config}>
<GridDetailPanel showExpandColumn animation="slide">
{({ row, rowIndex }) => (
<div className="detail-panel">
<h4>{row.name}'s Details</h4>
<p>Email: {row.email}</p>
<EmployeeHistory employeeId={row.id} />
</div>
)}
</GridDetailPanel>
</DataGrid>
);
}GridDetailPanel Props:
| Prop | Type | Default | Description |
|---|---|---|---|
children |
(ctx: DetailPanelContext) => ReactNode |
Required | Render function for panel content |
showExpandColumn |
boolean |
true |
Show expand/collapse chevron column |
animation |
'slide' | 'fade' | false |
'slide' |
Animation style for expand/collapse |
Custom Tool Panels with GridToolPanel
Add custom sidebar panels to the grid shell:
import { DataGrid, GridToolPanel, GridToolButtons } from '@toolbox-web/grid-react';
import { ShellPlugin } from '@toolbox-web/grid/all';
function EmployeeGrid() {
const config: ReactGridConfig<Employee> = {
columns: [...],
plugins: [new ShellPlugin()],
};
return (
<DataGrid rows={employees} gridConfig={config}>
{/* Toolbar buttons */}
<GridToolButtons>
<button onClick={handleExport}>Export CSV</button>
<button onClick={handlePrint}>Print</button>
</GridToolButtons>
{/* Custom sidebar panel */}
<GridToolPanel id="quick-filters" title="Quick Filters" icon="🔍" order={10}>
{({ grid }) => (
<div className="filter-panel">
<label>
Department:
<select onChange={(e) => applyFilter(grid, 'department', e.target.value)}>
<option value="">All</option>
<option value="Engineering">Engineering</option>
<option value="Marketing">Marketing</option>
</select>
</label>
</div>
)}
</GridToolPanel>
</DataGrid>
);
}GridToolPanel Props:
| Prop | Type | Default | Description |
|---|---|---|---|
id |
string |
Required | Unique panel identifier |
title |
string |
Required | Panel title in accordion header |
children |
(ctx: ToolPanelContext) => ReactNode |
Required | Render function for panel content |
icon |
string |
- | Icon for the accordion header |
tooltip |
string |
- | Tooltip text for header |
order |
number |
100 |
Panel sort order (lower = higher) |
Hooks
useGrid
Access the grid instance for programmatic control:
import { DataGrid, useGrid } from '@toolbox-web/grid-react';
function MyComponent() {
const { ref, isReady, forceLayout, getConfig } = useGrid<Employee>();
const handleExport = async () => {
const config = await getConfig();
console.log('Columns:', config?.columns);
};
return (
<>
<button onClick={handleExport}>Export</button>
<button onClick={() => forceLayout()}>Refresh Layout</button>
<DataGrid ref={ref} rows={employees} />
</>
);
}useGridEvent
Type-safe event subscription with automatic cleanup:
import { DataGrid, useGridEvent, DataGridRef } from '@toolbox-web/grid-react';
import { useRef } from 'react';
function MyComponent() {
const gridRef = useRef<DataGridRef>(null);
useGridEvent(gridRef, 'selection-change', (event) => {
console.log('Selected:', event.detail.selectedRows);
});
return <DataGrid ref={gridRef} rows={employees} />;
}Event Handling
Via Props
<DataGrid
rows={employees}
onCellEdit={(e) => console.log('Edited:', e.detail)}
onRowClick={(e) => console.log('Clicked:', e.detail.row)}
onSortChange={(e) => console.log('Sort:', e.detail)}
/>Via useGridEvent Hook
See useGridEvent above.
Type-Level Defaults
Define app-wide renderers and editors for custom column types using GridTypeProvider:
import { GridTypeProvider, DataGrid, type TypeDefaultsMap } from '@toolbox-web/grid-react';
import { EditingPlugin } from '@toolbox-web/grid/plugins/editing';
// Define type defaults at app level
const typeDefaults: TypeDefaultsMap = {
country: {
renderer: (ctx) => <span>🌍 {ctx.value}</span>,
editor: (ctx) => (
<select defaultValue={ctx.value} onChange={(e) => ctx.commit(e.target.value)}>
<option value="USA">USA</option>
<option value="UK">UK</option>
<option value="Germany">Germany</option>
</select>
),
},
currency: {
renderer: (ctx) => <span>${ctx.value.toFixed(2)}</span>,
},
};
// Wrap your app with the provider
function App() {
return (
<GridTypeProvider defaults={typeDefaults}>
<Dashboard />
</GridTypeProvider>
);
}
// All grids with type: 'country' columns use these components
function Dashboard() {
return (
<DataGrid
rows={employees}
gridConfig={{
columns: [
{ field: 'name', header: 'Name' },
{ field: 'country', type: 'country', editable: true },
{ field: 'salary', type: 'currency' },
],
plugins: [new EditingPlugin()],
}}
/>
);
}Hooks:
| Hook | Description |
|---|---|
useGridTypeDefaults() |
Get all type defaults from context |
useTypeDefault(type) |
Get defaults for a specific type |
Using Plugins
Import plugins individually for smaller bundles:
import { DataGrid } from '@toolbox-web/grid-react';
import { SelectionPlugin } from '@toolbox-web/grid/plugins/selection';
import { FilteringPlugin } from '@toolbox-web/grid/plugins/filtering';
function MyComponent() {
return (
<DataGrid
rows={employees}
gridConfig={{
columns: [...],
plugins: [
new SelectionPlugin({ mode: 'row' }),
new FilteringPlugin({ debounceMs: 200 }),
],
}}
/>
);
}Or import all plugins at once (larger bundle, but convenient):
import { SelectionPlugin, FilteringPlugin } from '@toolbox-web/grid/all';Custom Styles
Inject custom CSS into the grid:
<DataGrid
rows={employees}
customStyles={`
.my-custom-cell {
background: #f0f0f0;
padding: 8px;
}
`}
/>API Reference
Exported Components
| Component | Description |
|---|---|
DataGrid |
Main grid component wrapper |
GridColumn |
Declarative column with render props |
GridDetailPanel |
Master-detail expandable panel |
GridToolPanel |
Custom sidebar panel |
GridToolButtons |
Toolbar button container |
GridTypeProvider |
App-level type defaults context |
Exported Hooks
| Hook | Description |
|---|---|
useGrid |
Grid ref with ready state and methods |
useGridEvent |
Type-safe event subscription with cleanup |
useGridTypeDefaults() |
Get all type defaults from context |
useTypeDefault(type) |
Get defaults for a specific type |
Exported Types
import type {
ReactGridConfig,
ReactColumnConfig,
CellRenderContext,
ColumnEditorContext,
DetailPanelContext,
ToolPanelContext,
DataGridRef,
DataGridProps,
// Type-level defaults
ReactTypeDefault,
TypeDefaultsMap,
GridTypeProviderProps,
} from '@toolbox-web/grid-react';DataGrid Props
| Prop | Type | Description |
|---|---|---|
rows |
TRow[] |
Row data to display |
columns |
ColumnConfig[] |
Column definitions |
gridConfig |
GridConfig |
Full configuration object |
fitMode |
'stretch' | 'fit-columns' | 'auto-fit' |
Column sizing mode |
customStyles |
string |
CSS to inject into grid |
onRowsChange |
(rows: TRow[]) => void |
Rows changed callback |
onCellEdit |
(event: CustomEvent) => void |
Cell edited callback |
onRowClick |
(event: CustomEvent) => void |
Row clicked callback |
GridColumn Props
| Prop | Type | Description |
|---|---|---|
field |
string |
Field key in row object |
header |
string |
Column header text |
type |
'string' | 'number' | 'date' | 'boolean' |
Data type |
editable |
boolean |
Enable editing |
sortable |
boolean |
Enable sorting |
resizable |
boolean |
Enable column resizing |
width |
string | number |
Column width |
children |
(ctx: CellRenderContext) => ReactNode |
Custom renderer |
editor |
(ctx: ColumnEditorContext) => ReactNode |
Custom editor |
DataGridRef Methods
| Method | Description |
| ------------------------- | --------------------------- | -------------------- |
| getConfig() | Get effective configuration |
| ready() | Wait for grid ready |
| forceLayout() | Force layout recalculation |
| toggleGroup(key) | Toggle group expansion |
| registerStyles(id, css) | Register custom styles |
| unregisterStyles(id) | void | Remove custom styles |
ReactGridAdapter
The adapter class is exported for advanced use cases:
import { ReactGridAdapter } from '@toolbox-web/grid-react';In most cases, the DataGrid component handles adapter registration automatically.
Demo
See the full React demo at demos/employee-management/react/ which demonstrates:
- 15+ plugins with full configuration
- Custom editors (star rating, date picker, status select, bonus slider)
- Custom renderers (status badges, rating colors, top performer stars)
- Hooks for programmatic control
- Shell integration (header, tool panels)
- Master-detail expandable rows
Requirements
- React 18.0.0 or higher
@toolbox-web/grid>= 0.2.0
Development
# Build the library
bun nx build grid-react
# Run tests
bun nx test grid-react
# Lint
bun nx lint grid-reactSupport This Project
This grid is built and maintained by a single developer in spare time. If it saves you time or money, consider sponsoring to keep development going:
License
MIT