forms-data-grid
v1.0.2
Published
Standalone React + TypeScript data grid package.
Downloads
1,091
Maintainers
Readme
forms-data-grid
A standalone, feature-rich React + TypeScript data grid component. Sorting, filtering, pagination, inline editing, row selection, column pinning, export (CSV/Excel/JSON), charts, find/search, virtual scrolling, undo/redo, row grouping, pivoting, and more — tree-shakeable and themeable via CSS custom properties.
npm install forms-data-gridQuick Start
import 'forms-data-grid/styles.css';
import { DataGrid, type ColumnDef } from 'forms-data-grid';
interface User {
id: number;
name: string;
email: string;
}
const columns: ColumnDef<User>[] = [
{ field: 'id', headerName: 'ID', width: 80 },
{ field: 'name', headerName: 'Name', sortable: true },
{ field: 'email', headerName: 'Email', flex: 1 },
];
const data: User[] = [
{ id: 1, name: 'Ada', email: '[email protected]' },
];
export function App() {
return <DataGrid<User> columnDefs={columns} rowData={data} height={500} pagination />;
}ColumnDef Reference
| Property | Type | Default | Description |
|---|---|---|---|
| field | string | — | Data property key (supports nested like user.name) |
| colId | string | field | Unique column ID |
| headerName | string | field | Header display text |
| width | number | 120 | Initial width (px) |
| minWidth | number | 50 | Min resize width |
| maxWidth | number | 2000 | Max resize width |
| flex | number | — | Flex-grow ratio (overrides width) |
| hide | boolean | false | Initially hidden |
| pinned | 'left' \| 'right' \| null | null | Pin column |
| lockPinned | boolean | false | Prevent unpin |
| lockVisible | boolean | false | Prevent hide |
| resizable | boolean | true | Allow resize |
| sortable | boolean | true | Allow sort |
| comparator | (a,b,nodeA,nodeB)=>number | — | Custom sort fn |
| filter / filterable | boolean | true | Allow filter |
| filterType | 'text'\|'number'\|'date'\|'set' | 'text' | Filter type |
| floatingFilter | boolean | false | Inline filter input |
| editable | boolean\|(params)=>boolean | false | Allow edit |
| cellEditor | 'text'\|'number'\|'select'\|'date'\|fn | — | Editor |
| cellEditorParams | Record<string,unknown> | — | Editor params |
| valueSetter | (params)=>boolean | — | Custom write (return false to reject) |
| valueGetter | (params)=>CellValue | — | Computed value |
| valueFormatter | (params)=>string | — | Display format |
| cellRenderer | (params)=>ReactNode | — | Custom cell renderer |
| headerRenderer | (params)=>ReactNode | — | Custom header |
| cellClass | string\|(params)=>string | — | Cell CSS class |
| cellStyle | CSSProperties\|(params)=>CSSProperties | — | Cell inline style |
| checkboxSelection | boolean | false | Selection checkbox |
| headerCheckboxSelection | boolean | false | Select-all checkbox |
| rowDrag | boolean | false | Drag handle |
| suppressMenu | boolean | false | Hide column menu |
| suppressMovable | boolean | false | Prevent reorder |
| enableRowGroup | boolean | false | Allow grouping |
| enablePivot | boolean | false | Allow pivoting |
| enableValue | boolean | false | Use as value for agg/pivot |
| aggFunc | 'sum'\|'avg'\|'min'\|'max'\|'count'\|fn | — | Aggregation function |
| children | ColumnDef[] | — | Column group children |
| groupId | string | — | Group ID |
| exportValue | (params)=>string | — | Custom export format |
DataGrid Props
Data
| Prop | Type | Default | Description |
|---|---|---|---|
| rowData | TData[] | [] | Row data |
| getRowId | (params)=>string | — | Unique row ID fn |
| rowModelType | 'clientSide'\|'infinite'\|'serverSide' | 'clientSide' | Data strategy |
| pinnedTopRowData | TData[] | — | Pinned top rows |
| pinnedBottomRowData | TData[] | — | Pinned bottom rows |
Columns & Layout
| Prop | Type | Default | Description |
|---|---|---|---|
| columnDefs | ColumnDef[] | required | Column definitions |
| defaultColDef | Partial<ColumnDef> | — | Defaults for all columns |
| height | number\|string | '600px' | Grid height |
| width | number\|string | '100%' | Grid width |
| rowHeight | number | 40 | Row height (px) |
| headerHeight | number | 40 | Header height |
| floatingFiltersHeight | number | 30 | Filter row height |
| groupHeaderHeight | number | 40 | Group header height |
Sorting
| Prop | Type | Default | Description |
|---|---|---|---|
| multiSortKey | 'ctrl'\|'shift' | 'ctrl' | Multi-sort modifier |
| sortingOrder | SortDirection[] | ['asc','desc',null] | Sort cycle |
| unSortIcon | boolean | false | Show icon when unsorted |
Filtering
| Prop | Type | Default | Description |
|---|---|---|---|
| quickFilterText | string | — | Global search text |
| excludeHiddenColumnsFromQuickFilter | boolean | false | Skip hidden cols |
Editing
| Prop | Type | Default | Description |
|---|---|---|---|
| editType | 'fullRow'\|'cell' | 'fullRow' | Edit mode |
| singleClickEdit | boolean | false | Edit on single click |
| stopEditingWhenCellsLoseFocus | boolean | false | Auto-stop on blur |
| undoRedoCellEditing | boolean | false | Ctrl+Z/Y undo |
| undoRedoCellEditingLimit | number | 50 | Max undo steps |
| cellValidator | (params)=>boolean\|{valid,message} | — | Validate cells |
Selection
| Prop | Type | Default | Description |
|---|---|---|---|
| rowSelection | 'single'\|'multiple' | — | Selection mode |
| enableRangeSelection | boolean | false | Click+drag cell range |
| enableRangeHandle | boolean | false | Range drag handle |
| suppressRowDeselection | boolean | false | Prevent deselect |
Pagination
| Prop | Type | Default | Description |
|---|---|---|---|
| pagination | boolean | false | Enable pagination |
| paginationPageSize | number | 100 | Rows per page |
| paginationPageSizeSelector | number[]\|boolean | [10,25,50,100,500] | Options |
| suppressPaginationPanel | boolean | false | Hide controls |
Grouping & Pivoting
| Prop | Type | Default | Description |
|---|---|---|---|
| groupDisplayType | 'singleColumn'\|'multipleColumns'\|'groupRows' | — | Group style |
| groupDefaultExpanded | number | — | Auto-expand N levels |
| groupIncludeFooter | boolean | false | Group footers |
| pivotMode | boolean | false | Enable pivot |
Export
| Prop | Type | Default | Description |
|---|---|---|---|
| defaultCsvExportParams | CsvExportParams | — | CSV defaults |
| defaultExcelExportParams | ExcelExportParams | — | Excel defaults |
| defaultJsonExportParams | JsonExportParams | — | JSON defaults |
Export params: { fileName?, allColumns?, columnKeys?, onlySelected?, skipHeader?, skipGroups?, processCellCallback? }. CSV adds separator. Excel adds sheetName. JSON adds indent.
Charts
| Prop | Type | Default | Description |
|---|---|---|---|
| enableCharts | boolean | false | Enable chart creation |
UI
| Prop | Type | Default | Description |
|---|---|---|---|
| showToolbar | boolean | true | Show toolbar |
| statusBar | boolean | false | Show row counts |
| showRowNumbers | boolean | false | Row numbers |
| rowNumberColumnWidth | number | 50 | Row num width |
| rowAlternation | boolean | false | Striped rows |
| enableFind | boolean | true | Find/search |
Overlays & Styling
| Prop | Type | Default | Description |
|---|---|---|---|
| loadingOverlayComponent | ()=>ReactNode | — | Custom loading |
| noRowsOverlayComponent | ()=>ReactNode | — | Custom empty |
| rowClass | string\|(params)=>string | — | Row CSS class |
| getRowStyle | (params)=>CSSProperties | — | Row inline style |
Other
| Prop | Type | Default | Description |
|---|---|---|---|
| rowDragManaged | boolean | false | Row dragging |
| animateRows | boolean | false | Animate changes |
| treeData | boolean | false | Hierarchical data |
| getDataPath | (data)=>string[] | — | Tree path |
| masterDetail | boolean | false | Expandable detail |
| detailCellRenderer | (params)=>ReactNode | — | Detail content |
| detailRowHeight | number | 300 | Detail height |
| serverSideDatasource | ServerSideDatasource | — | Server data source |
| suppressContextMenu | boolean | false | Disable right-click |
| enableCellTextSelection | boolean | false | Text select in cells |
Events
| Event | When |
|---|---|
| onGridReady({api}) | Grid initialized |
| onCellClicked({data,colDef,value,rowIndex,node}) | Cell clicked |
| onCellDoubleClicked(...) | Cell double-clicked |
| onCellContextMenu({data,colDef,value,rowIndex,event}) | Right-click |
| onCellValueChanged({rowIndex,colDef,oldValue,newValue,data,source}) | Edit committed |
| onCellEditingStarted(...) | Edit began |
| onCellEditingStopped({...,cancelled}) | Edit ended |
| onRowClicked({data,node,rowIndex,event}) | Row clicked |
| onRowDataChanged() | Data mutated |
| onSelectionChanged({selectedRows}) | Selection changed |
| onFilterChanged({filterModel}) | Filter changed |
| onSortChanged({sortModel}) | Sort changed |
| onPaginationChanged({currentPage,totalPages,pageSize}) | Page changed |
| onRowDragEnd({node,overNode,overIndex}) | Drag end |
| onColumnResized({colId,width}) | Column resized |
Grid API
const [api, setApi] = useState(null);
<DataGrid onGridReady={({api}) => setApi(api)} />| Method | Description |
|---|---|
| api.selectAll() / api.deselectAll() | Select/deselect rows |
| api.getSelectedRows() / api.getSelectedNodes() | Get selection |
| api.setFilterModel(model) | Set filters |
| api.setSortModel(model) | Set sort |
| api.setQuickFilter(text) | Quick filter |
| api.exportCsv(params?) | Download CSV |
| api.exportExcel(params?) | Download Excel |
| api.exportJson(params?) | Download JSON |
| api.ensureIndexVisible(idx) | Scroll to row |
| api.ensureColumnVisible(colId) | Scroll to column |
| api.addRowGroupColumn(colId) | Group by column |
| api.removeRowGroupColumn(colId) | Ungroup |
| api.setColumnVisible(colId, visible) | Show/hide column |
| api.setColumnWidth(colId, width) | Set width |
| api.autoSizeColumn(colId) / api.autoSizeAllColumns() | Auto-size |
| api.resetState() | Reset all |
| api.showLoadingOverlay() / api.hideOverlay() | Overlays |
| api.applyTransaction({add?,remove?,update?}) | Modify data |
| api.startEditingCell({rowIndex,colId}) | Edit programmatically |
| api.stopEditing() | Stop editing |
| api.getFilterModel() / api.getSortModel() | Get current state |
Feature Examples
Sorting
<DataGrid multiSortKey="ctrl" unSortIcon /> // Ctrl+click for multi-sortFiltering
// Column filter types
{ field: 'name', filter: true, filterType: 'text' }
{ field: 'age', filter: true, filterType: 'number' }
{ field: 'country', filter: true, filterType: 'set' }
// Floating inline filters
{ field: 'name', floatingFilter: true }
// Quick filter (toolbar)
<DataGrid quickFilterText={q} onQuickFilterChange={setQ} />Inline Editing
<DataGrid
columnDefs={[
{ field: 'name', editable: true, cellEditor: 'text' },
{ field: 'status', editable: true, cellEditor: 'select', cellEditorParams: { options: ['A','B'] } },
{ field: 'email', editable: true, valueSetter: (p) => {
if (!String(p.newValue).includes('@')) return false;
p.data.email = String(p.newValue);
return true;
}},
]}
undoRedoCellEditing
/>
// Double-click to edit, Enter=commit, Escape=cancel, Ctrl+Z/Y=undo/redoCustom Rendering
{ field: 'revenue', valueFormatter: (p) => `$${p.value.toLocaleString()}` }
{ field: 'fullName', valueGetter: (p) => `${p.data.first} ${p.data.last}` }
{ field: 'status', cellRenderer: (p) => <Badge>{p.value}</Badge> }
{ field: 'revenue', cellClass: (p) => p.value > 1000 ? 'text-green-600' : '' }Pagination
<DataGrid pagination paginationPageSize={25} paginationPageSizeSelector={[10,25,50]} />Row Selection
<DataGrid
columnDefs={[
{ checkboxSelection: true, headerCheckboxSelection: true, width: 50, pinned: 'left' },
{ field: 'name' },
]}
rowSelection="multiple"
/>Column Pinning & Groups
{ field: 'id', pinned: 'left', width: 80 }
// Column groups:
{ headerName: 'Contact', children: [{ field: 'name' }, { field: 'email' }] }Pivoting
<DataGrid
columnDefs={[
{ field: 'hall', enablePivot: true },
{ field: 'revenue', enableValue: true, aggFunc: 'sum' },
]}
/>
// Right-click column header → "Pivot by This"
// Pivot columns appear. "Pivot ON ×" button in toolbar to disable.Charts
<DataGrid enableCharts />
// 1. Click+drag cells to select range
// 2. Click Charts toolbar button
// 3. Choose type: bar, line, pie, scatter, area, doughnut
// Chart renders with axis labels, legend, and resize drag-handleExport
<DataGrid
defaultCsvExportParams={{ fileName: 'data', separator: ',' }}
defaultExcelExportParams={{ fileName: 'data', sheetName: 'Sheet1' }}
/>
// Toolbar: Export → CSV/Excel/JSON. Exports FULL dataset, not just current page.Context Menu
<DataGrid getContextMenuItems={(p) => [
{ name: '📋 Copy', action: () => navigator.clipboard.writeText(String(p.value)) },
{ name: '', action: () => {}, separator: true },
{ name: '🔍 Filter', action: () => { /* filter by p.value */ } },
]} />Row Transactions
api.applyTransaction({ add: [{ id: 99, name: 'New' }], addIndex: 0 });
api.applyTransaction({ update: [{ id: 1, name: 'Updated' }] });
api.applyTransaction({ remove: [{ id: 2 }] });Server-Side
<DataGrid
rowModelType="serverSide"
serverSideDatasource={{
getRows: (params) => fetch('/api?' + new URLSearchParams({
start: params.request.startRow, end: params.request.endRow,
})).then(r => r.json()).then(r => params.success({ rowData: r.rows, rowCount: r.total })),
}}
pagination
/>Dark Mode
import { initializeDataGridTheme, useDataGridAppearance } from 'forms-data-grid';
initializeDataGridTheme(); // once at root
// Toggle via toolbar ☀/🌙 buttonStyling
Overwrite CSS custom properties inside .forms-data-grid-theme:
.forms-data-grid-theme {
--forms-data-grid-background: #fff;
--forms-data-grid-foreground: #1a1a2e;
--forms-data-grid-border: #e2e8f0;
--forms-data-grid-radius: 0.5rem;
}Dark mode: .forms-data-grid-dark .forms-data-grid-theme { ... }
Required import: import 'forms-data-grid/styles.css';
Package Exports
export { DataGrid, DataGridProvider, useDataGridContext } from 'forms-data-grid';
export { initializeDataGridTheme, useDataGridAppearance } from 'forms-data-grid';
export type {
ColumnDef, ResolvedColumn, CellValue, DataGridProps, GridApi,
FilterModel, SortModel, CsvExportParams, ExcelExportParams,
RowNode, RowTransaction, ChartOptions, ChartState,
} from 'forms-data-grid';Development
npm install && npm run buildPeer deps: react ^18/^19, react-dom ^18/^19
