@utiltools/datagrid
A lightweight, TypeScript-first React data grid with sorting, filtering, pagination and row selection.
Installation
Or use yarn or pnpm:
Quick Start
import { DataGrid } from '@utiltools/datagrid';
import type { ColumnDef } from '@utiltools/datagrid';
interface User {
id: number;
name: string;
email: string;
role: string;
}
function App() {
const data: User[] = [
{ id: 1, name: 'Alice', email: '[email protected]', role: 'Admin' },
{ id: 2, name: 'Bob', email: '[email protected]', role: 'User' },
];
const columns: ColumnDef<User>[] = [
{ key: 'name', label: 'Name', sortable: true, filterable: true },
{ key: 'email', label: 'Email', sortable: true },
{ key: 'role', label: 'Role', sortable: true },
];
return (
<DataGrid
data={data}
columns={columns}
rowKey="id"
pageSize={10}
searchable
/>
);
}Features
Sorting
Click column headers to sort ascending or descending
Filtering
Column-level filters with global search
Pagination
Built-in pagination with customizable page sizes
Row Selection
Single or multi-row selection with checkboxes
Custom Rendering
Full control over cell rendering with render functions
TypeScript Support
Full type safety with generic row types
Loading States
Built-in loading skeleton UI
Responsive
Works great on mobile and desktop
API Reference
DataGrid Props
| Prop | Type | Default | Description |
|---|---|---|---|
| data | TRow[] | required | Array of row objects to display |
| columns | ColumnDef<TRow>[] | required | Column definitions |
| rowKey | keyof TRow | index | Field to use as unique row identifier |
| pageSize | number | 10 | Number of rows per page |
| pageSizeOptions | number[] | [10, 25, 50, 100] | Available page size options in the dropdown |
| selectable | boolean | false | Enable row selection checkboxes |
| striped | boolean | false | Alternate row background colors |
| searchable | boolean | true | Show global search input in the toolbar |
| searchPlaceholder | string | "Search…" | Placeholder text for the global search input |
| loading | boolean | false | Show loading skeleton instead of data rows |
| emptyMessage | string | "No data to display." | Message shown when data array is empty |
| className | string | "" | Additional CSS classes applied to the outer wrapper |
| onSelectionChange | (keys: Set<string>) => void | undefined | Fired whenever the selected row keys change |
ColumnDef Type
interface ColumnDef<T> {
key: keyof T & string; // must match a property in your row objects
label: string; // column header text
sortable?: boolean; // enable sort on click (default: false)
filterable?: boolean; // show per-column filter input (default: false)
width?: number; // fixed pixel width
minWidth?: number; // minimum width
align?: 'left' | 'center' | 'right';
render?: (value: unknown, row: T, rowIndex: number) => string; // HTML string
hidden?: boolean; // exclude from render
}Examples
Custom Cell Rendering
const columns: ColumnDef<User>[] = [
{
key: 'status',
label: 'Status',
sortable: true,
align: 'center',
// render returns an HTML string
render: (value) => {
const color = value === 'Active' ? 'green' : 'gray';
return `<span style="color:${color};font-weight:600">${value}</span>`;
},
},
{
key: 'salary',
label: 'Salary',
sortable: true,
align: 'right',
render: (value) =>
typeof value === 'number' ? `$${value.toLocaleString()}` : '—',
},
];Column Filtering
Set filterable: true on any column to show a filter input beneath its header. Active filters appear as removable chips above the table.
const columns: ColumnDef<User>[] = [
{ key: 'name', label: 'Name', sortable: true, filterable: true },
{ key: 'department', label: 'Department', sortable: true, filterable: true },
{ key: 'salary', label: 'Salary', sortable: true },
];
// Global search across all columns is on by default.
// Turn it off with searchable={false}
<DataGrid data={data} columns={columns} rowKey="id" searchable />Row Selection
function MyGrid() {
const [selected, setSelected] = useState<Set<string>>(new Set());
return (
<>
<p>{selected.size} rows selected</p>
<DataGrid
data={data}
columns={columns}
rowKey="id"
selectable
onSelectionChange={setSelected}
/>
</>
);
}Striped Rows
<DataGrid
data={data}
columns={columns}
rowKey="id"
striped
/>Server-side operations
The current version performs all sorting, filtering, and pagination client-side — pass your full dataset as data and the grid handles the rest. Server-side sorting, filtering, and pagination (for very large datasets fetched page-by-page from an API) is planned as a Pro feature in an upcoming release.