npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

forms-data-grid

v1.0.2

Published

Standalone React + TypeScript data grid package.

Downloads

1,091

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-grid

Quick 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-sort

Filtering

// 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/redo

Custom 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-handle

Export

<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 ☀/🌙 button

Styling

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 build

Peer deps: react ^18/^19, react-dom ^18/^19