A high-performance React DataTable with sorting, filtering, and aggregation.
npm install react-pro-datatablebash
npm install react-pro-datatable
or
yarn add react-pro-datatable
or
pnpm add react-pro-datatable
`
Quick Start
`tsx
import React from 'react';
import { DataGrid, Column } from 'react-pro-datatable';
import 'react-pro-datatable/dist/style.css';// Import styles
// --- Mock Data ---
interface User {
id: number;
firstName: string;
lastName: string;
email: string;
age: number;
status: string;
visits: number;
progress: number;
}
const generateData = (count: number): User[] => {
const statuses = ['Active', 'Inactive', 'Pending', 'Banned'];
return Array.from({ length: count }).map((_, i) => ({
id: i + 1,
firstName: ['John', 'Jane', 'Bob', 'Alice', 'Charlie'][i % 5],
lastName: ['Doe', 'Smith', 'Johnson', 'Brown', 'Davis'][i % 5],
email: user${i + 1}@example.com,
age: 20 + (i % 40),
status: statuses[i % 4],
visits: Math.floor(Math.random() * 100),
progress: Math.floor(Math.random() * 100),
}));
};
const App = () => {
const [data, setData] = useState([]);
const [loading, setLoading] = useState(true);
const [darkMode, setDarkMode] = useState(false);
// Initialize from storage or empty
const [pinnedRows, setPinnedRows] = useState<{ top: any[]; bottom: any[] }>(() => {
try {
const saved = localStorage.getItem('demo_table_pinned_rows');
return saved ? JSON.parse(saved) : { top: [], bottom: [] };
} catch {
return { top: [], bottom: [] };
}
});
// Persist pinned rows
useEffect(() => {
localStorage.setItem('demo_table_pinned_rows', JSON.stringify(pinnedRows));
}, [pinnedRows]);
// Simulate initial data fetch
useEffect(() => {
const timer = setTimeout(() => {
setData(generateData(100));
setLoading(false);
}, 1500);
return () => clearTimeout(timer);
}, []);
const columns: Column[] = [
{
key: 'id',
label: 'ID',
width: 80,
sortable: true,
},
{ key: 'firstName', label: 'First Name', sortable: true, filterable: true, width: 120, editable: true },
{ key: 'lastName', label: 'Last Name', sortable: true, filterable: true, width: 120, editable: true },
{
key: 'email',
label: 'Email',
width: 200,
editable: true,
headerActions: [
{
label: 'Email All',
onClick: () => alert('Action: Emailing all visible users...'),
icon: 📧
}
]
},
{
key: 'status',
label: 'Status',
width: 100,
sortable: true,
render: (val) => {
let statusClass = 'status-inactive';
if (val === 'Active') statusClass = 'status-active';
else if (val === 'Pending') statusClass = 'status-pending';
else if (val === 'Banned') statusClass = 'status-banned';
return (
status-badge ${statusClass}}>
{val}
);
},
headerActions: [
{
label: 'Archive Inactive',
onClick: () => alert('Archiving inactive users...'),
danger: true
}
]
},
{ key: 'visits', label: 'Visits', sortable: true, aggregator: 'SUM', editable: true },
{
key: 'progress',
label: 'Progress',
width: 150,
aggregator: 'AVG',
render: (val) => (
${val}% }}>
)
},
];
const handleBulkDelete = (selected: User[]) => {
alert( Deleting ${selected.length} users: ${selected.map(u => u.id).join(', ')});
};
const processRowUpdate = (newRow: User, oldRow: User) => {
// Simulate backend update
return new Promise((resolve, reject) => {
setTimeout(() => {
if (newRow.firstName.trim() === '') {
alert("First name cannot be empty");
reject("First name empty");
return;
}
setData(prev => prev.map(row => row.id === newRow.id ? newRow : row));
resolve(newRow);
}, 200);
});
};
return (
app-container ${darkMode ? 'dark' : ''}}>
storageKey="demo_table_v1"
loading={loading}
rows={data}
columns={columns}
title="User Management"
subtitle="Manage system users and permissions"
checkboxSelection
enableBulkActions
disableGlobalSearch={false}
disableColumnResize={false}
pageSizeOptions={[10, 25, 100]}
darkMode={darkMode}
// Unpin all columns by default
initialState={{
pagination: { pageIndex: 0, pageSize: 10 },
pinnedColumns: {}
}}
// Row Pinning with state management
pinnedRows={pinnedRows}
onPinnedRowsChange={setPinnedRows}
processRowUpdate={processRowUpdate}
bulkActions={[
{ label: 'Delete Selected', onClick: handleBulkDelete }
]}
onRowSelectionModelChange={(ids) => console.log('Selection:', ids)}
/>
);
};
export default App;
`
Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| Core Props | | | |
| rows | T[] | [] | Array of data objects to display (Required). |
| columns | Column | [] | Configuration for table columns (Required). |
| loading | boolean | false | Set to true to show a loading overlay. |
| darkMode | boolean | false | Toggle built-in dark mode theme. |
| idField | string | 'id' | The unique identifier field in your data. |
| State & Storage | | | |
| initialState | object | - | Initial state for pagination, sorting, filters, globalSearch, pinnedColumns, and visibility. |
| storageKey | string | - | Unique key to persist state (visibility, pinned columns) in localStorage. |
| Pagination | | | |
| paginationMode | 'client' \| 'server' | 'client' | Switch between client-side and server-side pagination. |
| pageSizeOptions | number[] | [5, 10, 20, 50] | Options available in the page size selector. |
| rowCount | number | - | Total number of rows (required for server pagination). |
| onPaginationModelChange | (model) => void | - | Callback when page or page size changes. |
| Selection & Pining | | | |
| checkboxSelection | boolean | false | Enable checkbox selection for rows. |
| enableRowPinning | boolean | true | Allow users to pin rows to top/bottom via context menu. |
| pinnedRows | PinnedRowsState | - | Controlled state for pinned rows ({ top: [], bottom: [] }). |
| onPinnedRowsChange | (pinnedRows) => void | - | Callback when pinned rows change. |
| onRowSelectionModelChange | (selectedIds) => void | - | Callback when selected rows change. |
| Features & Flags | | | |
| disableColumnPinning | boolean | false | Disable column pinning feature. |
| disableColumnSorting | boolean | false | Disable column sorting feature. |
| disableColumnFilter | boolean | false | Disable column filtering feature. |
| disableColumnMenu | boolean | false | Disable the column actions menu. |
| disableColumnResize | boolean | false | Disable column resizing. |
| disableGlobalSearch | boolean | false | Hide the global search bar. |
| disableExport | boolean | false | Hide the export (download) button. |
| enableBulkActions | boolean | false | Show bulk action buttons when rows are selected. |
| bulkActions | { label, onClick }[] | [] | Array of bulk action objects. |
| Header & Layout | | | |
| title | ReactNode | - | Title displayed in the toolbar. |
| subtitle | ReactNode | - | Subtitle displayed in the toolbar. |
| className | string | - | Custom class for the main container. |
| headerClassName | string | - | Custom class for the table header . |
| rowClassName | string | - | Custom class for table rows . |
| footerClassName | string | - | Custom class for the footer area. |
| toolbarClassName | string | - | Custom class for the toolbar area. |
| Callbacks | | | |
| onSortModelChange | (model) => void | - | Callback when sorting changes. |
| onFilterModelChange | (model) => void | - | Callback when filters change. |
| onColumnVisibilityChange | (model) => void | - | Callback when column visibility changes. |
| processRowUpdate | (newRow, oldRow) => T | - | Function called when a cell is edited and saved. Return the updated row. |
| onProcessRowUpdateError | (error) => void | - | Callback if processRowUpdate fails. |
Column Definition (
Column)
| Property | Type | Description |
|----------|------|-------------|
| key | string | Unique key for the column (matches data field). |
| label | string | Header display text. |
| width | number | Initial width of the column. |
| minWidth | number | Minimum width of the column. |
| render | (value, row) => Node | Custom renderer for cell content. |
| sortable | boolean | Enable sorting for this column. |
| filterable | boolean | Enable filtering for this column. |
| editable | boolean | Enable inline editing for this column. |
| aggregator | 'sum' \| 'avg' \| ... | Aggregation function for footer (if implemented). |
Styling
The library ships with a default CSS file:
`tsx
import 'react-pro-datatable/dist/style.css';
`
You can override CSS variables to match your theme:
`css
:root {
--dt-primary: #3b82f6;
--dt-bg: #ffffff;
--dt-border: #e5e7eb;
/ See style.css for full list /
}
``