@ackplus/react-tanstack-data-table
v1.0.35
Published
A powerful React data table component built with MUI and TanStack Table
Readme
@ackplus/react-tanstack-data-table
A powerful, feature-rich, and highly customizable React data table component built with Material-UI (MUI) and TanStack Table. Perfect for building modern data-intensive applications with advanced table functionality.
🚀 Live Demo
Experience all the features in action with our interactive demo showcasing advanced table functionality, filtering, sorting, pagination, and more.
✨ Features
- 🚀 High Performance: Built on TanStack Table for excellent performance with large datasets
- 🎨 Material Design: Beautiful UI components using MUI with consistent design system
- 📱 Responsive: Mobile-friendly responsive design with adaptive layouts
- 🔍 Advanced Filtering: Global search, column filters, and filter components
- 📊 Multi-Column Sorting: Powerful sorting with multiple columns support
- 📄 Flexible Pagination: Client-side and server-side pagination options
- 🎯 Column Management: Show/hide, resize, reorder, and pin columns
- 📤 Data Export: Export to CSV/Excel with progress tracking and customization
- 🖱️ Row Selection: Single and multi-row selection with bulk actions
- ⚡ Virtualization: Handle large datasets efficiently with row virtualization
- 🔄 Server Integration: Built-in support for server-side operations
- 🎛️ Highly Customizable: Extensive customization through slots and props
- 📝 TypeScript: Full TypeScript support with comprehensive type definitions
- 🔌 Extensible: Plugin architecture with custom components and hooks
- 🛠️ Debug Logging: Configurable console instrumentation with global or per-table controls
📦 Installation
npm install @ackplus/react-tanstack-data-tableyarn add @ackplus/react-tanstack-data-tablepnpm add @ackplus/react-tanstack-data-table🔧 Peer Dependencies
Make sure you have the following peer dependencies installed:
npm install @emotion/react @emotion/styled @mui/icons-material @mui/material @tanstack/react-table @tanstack/react-virtual react react-dom🚀 Quick Start
import React from 'react';
import { DataTable } from '@ackplus/react-tanstack-data-table';
import { createColumnHelper } from '@tanstack/react-table';
interface User {
id: number;
name: string;
email: string;
status: 'active' | 'inactive';
role: string;
}
const columnHelper = createColumnHelper<User>();
const columns = [
columnHelper.accessor('name', {
header: 'Name',
size: 150,
}),
columnHelper.accessor('email', {
header: 'Email',
size: 200,
}),
columnHelper.accessor('status', {
header: 'Status',
cell: ({ getValue }) => (
<Chip
label={getValue()}
color={getValue() === 'active' ? 'success' : 'default'}
/>
),
}),
columnHelper.accessor('role', {
header: 'Role',
size: 120,
}),
];
const data: User[] = [
{ id: 1, name: 'John Doe', email: '[email protected]', status: 'active', role: 'Admin' },
{ id: 2, name: 'Jane Smith', email: '[email protected]', status: 'inactive', role: 'User' },
// ... more data
];
function MyDataTable() {
return (
<DataTable
columns={columns}
data={data}
enableSorting
enableGlobalFilter
enablePagination
enableRowSelection
enableColumnVisibility
enableExport
/>
);
}📋 Core Props
Basic Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| columns | DataTableColumn<T>[] | Required | Column definitions array |
| data | T[] | [] | Array of data objects |
| idKey | keyof T | 'id' | Unique identifier key for rows |
| loading | boolean | false | Loading state indicator |
| emptyMessage | string | 'No data available' | Message when no data |
Data Management
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| dataMode | 'client' \| 'server' | 'client' | Data management mode |
| initialLoadData | boolean | true | Load data on component mount |
| onFetchData | (filters) => Promise<{data, total}> | - | Server-side data fetching |
| onDataStateChange | (state) => void | - | Called when table state changes |
| totalRow | number | 0 | Total rows for server-side pagination |
Selection & Interaction
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| enableRowSelection | boolean \| ((row) => boolean) | false | Enable row selection |
| enableMultiRowSelection | boolean | true | Allow multiple row selection |
| selectMode | 'page' \| 'all' | 'page' | Selection scope (page or all data) |
| isRowSelectable | (params: {row: T, id: string}) => boolean | - | Control if specific row is selectable |
| onSelectionChange | (selection: SelectionState) => void | - | Selection state change callback |
| enableBulkActions | boolean | false | Enable bulk actions toolbar |
| bulkActions | (selectionState: SelectionState) => ReactNode | - | Custom bulk actions component |
Selection State
The SelectionState interface provides detailed information about the current selection:
interface SelectionState {
ids: string[]; // Array of selected/excluded row IDs
type: 'include' | 'exclude'; // Selection mode
}- Include mode:
idscontains the selected row IDs - Exclude mode:
idscontains the excluded row IDs (all others are selected)
This allows for efficient handling of large datasets where you might select "all except these few".
Pagination
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| enablePagination | boolean | true | Enable pagination |
| paginationMode | 'client' \| 'server' | 'client' | Pagination mode |
| onPaginationChange | (pagination: PaginationState) => void | - | Pagination change callback |
| initialState.pagination | {pageIndex: number, pageSize: number} | {pageIndex: 0, pageSize: 50} | Initial pagination state |
Filtering & Search
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| enableGlobalFilter | boolean | true | Enable global search |
| enableColumnFilter | boolean | false | Enable individual column filters |
| filterMode | 'client' \| 'server' | 'client' | Filtering mode |
| onColumnFiltersChange | (filterState: ColumnFilterState) => void | - | Column filters change callback |
| onGlobalFilterChange | (globalFilter: string) => void | - | Global filter change callback |
| onColumnFilterChange | (columnFilter: ColumnFilterState) => void | - | Column filter change callback |
| extraFilter | ReactNode | - | Additional filter components |
Sorting
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| enableSorting | boolean | true | Enable column sorting |
| sortingMode | 'client' \| 'server' | 'client' | Sorting mode |
| onSortingChange | (sorting) => void | - | Sorting change callback |
Column Management
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| enableColumnVisibility | boolean | true | Show/hide columns control |
| enableColumnResizing | boolean | false | Allow column resizing |
| columnResizeMode | ColumnResizeMode | 'onChange' | Column resize mode |
| enableColumnPinning | boolean | false | Allow column pinning |
| enableColumnDragging | boolean | false | Enable column reordering |
| onColumnDragEnd | (order: string[]) => void | - | Column reorder callback |
| onColumnPinningChange | (pinning: ColumnPinningState) => void | - | Column pinning callback |
Export Features
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| enableExport | boolean | true | Enable data export |
| exportFilename | string | 'export' | Default export filename |
| onExportProgress | (progress: {processedRows?, totalRows?, percentage?}) => void | - | Export progress callback |
| onExportComplete | (result: {success: boolean, filename: string, totalRows: number}) => void | - | Export completion callback |
| onExportError | (error: {message: string, code: string}) => void | - | Export error callback |
| onServerExport | (filters?: Partial<TableState>, selection?: SelectionState) => Promise<{data: any[], total: number}> | - | Server-side export handler |
| onExportCancel | () => void | - | Export cancellation callback |
Expandable Rows (Enhanced Slot System)
Expandable rows are now fully integrated with the enhanced slot system, providing better customization and type safety.
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| enableExpanding | boolean | false | Enable row expansion |
| getRowCanExpand | (row) => boolean | - | Determine if row can expand |
| renderSubComponent | (row) => ReactNode | - | Render expanded row content |
The expanding column is automatically added and can be customized through slotProps.expandColumn (see Special Column Configuration section above).
Styling & Layout
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| tableSize | 'small' \| 'medium' | 'medium' | Table size/density |
| enableHover | boolean | true | Row hover effects |
| enableStripes | boolean | false | Alternating row colors |
| fitToScreen | boolean | true | Fit table to container width |
| enableStickyHeaderOrFooter | boolean | false | Sticky header/footer |
| maxHeight | string \| number | '400px' | Max table height |
| tableContainerProps | object | {} | Props for table container |
| tableProps | object | {} | Props for table element |
Virtualization
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| enableVirtualization | boolean | false | Enable row virtualization |
| estimateRowHeight | number | 52 | Estimated row height for virtualization |
Advanced Customization
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| slots | Partial<DataTableSlots<T>> | {} | Custom component slots |
| slotProps | PartialSlotProps<T> | {} | Props for slot components |
| initialState | Partial<TableState> | {} | Initial table state |
| skeletonRows | number | 5 | Number of skeleton rows for loading state |
| footerFilter | ReactNode | - | Additional filter components in footer |
Special Column Configuration (Enhanced Slot System)
Special columns (selection and expanding) are now handled through the enhanced slot system, providing better customization and type safety.
Selection Column Configuration
The selection column is automatically added when enableRowSelection is true and can be customized through slotProps.selectionColumn:
<DataTable
data={data}
columns={columns}
enableRowSelection
enableMultiRowSelection
slotProps={{
selectionColumn: {
width: 80,
pinLeft: true,
id: 'custom-selection',
// Custom column configuration
header: ({ table }) => (
<Checkbox
checked={table.getIsAllRowsSelected()}
indeterminate={table.getIsSomeRowsSelected()}
onChange={() => table.toggleAllRowsSelected()}
sx={{ color: 'primary.main' }}
/>
),
cell: ({ row, table }) => (
<Checkbox
checked={table.getIsRowSelected(row.id)}
onChange={() => table.toggleRowSelected(row.id)}
sx={{ color: 'secondary.main' }}
/>
),
},
}}
/>Expanding Column Configuration
The expanding column is automatically added when enableExpanding is true and can be customized through slotProps.expandColumn:
<DataTable
data={data}
columns={columns}
enableExpanding
getRowCanExpand={(row) => row.original.details != null}
renderSubComponent={(row) => (
<Box p={2}>
<Typography variant="h6">Details</Typography>
<pre>{JSON.stringify(row.original.details, null, 2)}</pre>
</Box>
)}
slotProps={{
expandColumn: {
width: 60,
pinLeft: true,
id: 'custom-expand',
// Custom column configuration
header: 'Expand',
cell: ({ row }) => (
<IconButton
onClick={row.getToggleExpandedHandler()}
size="small"
sx={{ color: 'primary.main' }}
>
{row.getIsExpanded() ? <ExpandLessIcon /> : <ExpandMoreIcon />}
</IconButton>
),
},
}}
/>Advanced Special Column Customization
You can completely replace the special column components using the slots system:
import { createSelectionColumn, createExpandingColumn } from '@ackplus/react-tanstack-data-table';
function CustomTable() {
// Create custom selection column
const customSelectionColumn = createSelectionColumn({
width: 100,
pinLeft: true,
header: ({ table }) => (
<Tooltip title="Select All">
<Checkbox
checked={table.getIsAllRowsSelected()}
indeterminate={table.getIsSomeRowsSelected()}
onChange={() => table.toggleAllRowsSelected()}
sx={{
color: 'primary.main',
'&.Mui-checked': { color: 'primary.main' }
}}
/>
</Tooltip>
),
cell: ({ row, table }) => (
<Tooltip title="Select Row">
<Checkbox
checked={table.getIsRowSelected(row.id)}
onChange={() => table.toggleRowSelected(row.id)}
sx={{
color: 'secondary.main',
'&.Mui-checked': { color: 'secondary.main' }
}}
/>
</Tooltip>
),
});
// Create custom expanding column
const customExpandingColumn = createExpandingColumn({
width: 80,
pinLeft: true,
header: 'Details',
cell: ({ row }) => (
<Tooltip title={row.getIsExpanded() ? "Collapse" : "Expand"}>
<IconButton
onClick={row.getToggleExpandedHandler()}
size="small"
sx={{
color: 'primary.main',
transition: 'transform 0.2s',
transform: row.getIsExpanded() ? 'rotate(180deg)' : 'rotate(0deg)',
}}
>
<KeyboardArrowDownIcon />
</IconButton>
</Tooltip>
),
});
return (
<DataTable
data={data}
columns={[customSelectionColumn, customExpandingColumn, ...columns]}
enableRowSelection
enableExpanding
// ... other props
/>
);
}Special Column Configuration Options
| Property | Type | Default | Description |
|----------|------|---------|-------------|
| width | number | 60 | Column width in pixels |
| pinLeft | boolean | false | Pin column to the left |
| id | string | Auto-generated | Custom column ID |
| header | ReactNode \| (props) => ReactNode | Default header | Custom header component |
| cell | (props) => ReactNode | Default cell | Custom cell component |
| sx | SxProps | {} | Custom styling |
| className | string | - | Custom CSS class |
| style | CSSProperties | - | Custom inline styles |
Utility Functions for Special Columns
The library provides utility functions to create custom special columns:
Note: Special columns are now handled through the enhanced slot system instead of table props. This provides better type safety, more customization options, and consistent behavior with the rest of the component system.
import { createSelectionColumn, createExpandingColumn } from '@ackplus/react-tanstack-data-table';
// Create a custom selection column
const customSelectionColumn = createSelectionColumn({
width: 100,
pinLeft: true,
multiSelect: true, // Enable multi-select
header: ({ table }) => (
<Tooltip title="Select All Rows">
<Checkbox
checked={table.getIsAllRowsSelected()}
indeterminate={table.getIsSomeRowsSelected()}
onChange={() => table.toggleAllRowsSelected()}
sx={{ color: 'primary.main' }}
/>
</Tooltip>
),
cell: ({ row, table }) => (
<Tooltip title="Select Row">
<Checkbox
checked={table.getIsRowSelected(row.id)}
onChange={() => table.toggleRowSelected(row.id)}
sx={{ color: 'secondary.main' }}
/>
</Tooltip>
),
});
// Create a custom expanding column
const customExpandingColumn = createExpandingColumn({
width: 80,
pinLeft: true,
header: 'Details',
cell: ({ row }) => (
<Tooltip title={row.getIsExpanded() ? "Collapse Details" : "Expand Details"}>
<IconButton
onClick={row.getToggleExpandedHandler()}
size="small"
sx={{
color: 'primary.main',
transition: 'all 0.2s ease',
transform: row.getIsExpanded() ? 'rotate(180deg)' : 'rotate(0deg)',
'&:hover': {
backgroundColor: 'primary.light',
color: 'primary.contrastText',
},
}}
>
<KeyboardArrowDownIcon />
</IconButton>
</Tooltip>
),
});
// Use in your table
<DataTable
columns={[customSelectionColumn, customExpandingColumn, ...columns]}
data={data}
enableRowSelection
enableExpanding
// ... other props
/>🔥 Advanced Examples
Server-Side Data Management
import { DataTable } from '@ackplus/react-tanstack-data-table';
import { useState, useCallback } from 'react';
function ServerSideTable() {
const [loading, setLoading] = useState(false);
const fetchData = useCallback(async (filters) => {
setLoading(true);
try {
const response = await fetch('/api/users', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(filters),
});
const result = await response.json();
return { data: result.users, total: result.total };
} finally {
setLoading(false);
}
}, []);
return (
<DataTable
columns={columns}
dataMode="server"
loading={loading}
onFetchData={fetchData}
enablePagination
enableSorting
enableGlobalFilter
paginationMode="server"
sortingMode="server"
filterMode="server"
/>
);
}Row Selection with Bulk Actions and Enhanced Slot System
import { CheckCircleIcon, RadioButtonUncheckedIcon } from '@mui/icons-material';
function SelectableTable() {
const [selectedUsers, setSelectedUsers] = useState([]);
const bulkActions = (selectionState) => {
// Calculate selected count based on selection type
const selectedCount = selectionState.type === 'include'
? selectionState.ids.length
: data.length - selectionState.ids.length;
// Get actual selected data
const selectedRows = selectionState.type === 'include'
? data.filter(item => selectionState.ids.includes(item.id.toString()))
: data.filter(item => !selectionState.ids.includes(item.id.toString()));
return (
<Stack direction="row" spacing={1}>
<Button
variant="contained"
color="error"
onClick={() => deleteUsers(selectedRows)}
>
Delete ({selectedCount})
</Button>
<Button
variant="outlined"
onClick={() => exportUsers(selectedRows)}
>
Export Selected
</Button>
</Stack>
);
};
return (
<DataTable
columns={columns}
data={data}
enableRowSelection
enableMultiRowSelection
enableBulkActions
bulkActions={bulkActions}
onSelectionChange={setSelectedUsers}
slotProps={{
selectionColumn: {
width: 80,
pinLeft: true,
header: ({ table }) => (
<Checkbox
checked={table.getIsAllRowsSelected()}
indeterminate={table.getIsSomeRowsSelected()}
onChange={() => table.toggleAllRowsSelected()}
sx={{
color: 'primary.main',
'&.Mui-checked': { color: 'primary.main' }
}}
/>
),
cell: ({ row, table }) => (
<Checkbox
checked={table.getIsRowSelected(row.id)}
onChange={() => table.toggleRowSelected(row.id)}
sx={{
color: 'secondary.main',
'&.Mui-checked': { color: 'secondary.main' }
}}
/>
),
},
}}
/>
);
}Column Filters
const columns = [
{
accessorKey: 'status',
header: 'Status',
filterable: true,
type: 'select',
options: [
{ value: 'active', label: 'Active' },
{ value: 'inactive', label: 'Inactive' },
{ value: 'pending', label: 'Pending' },
],
},
{
accessorKey: 'priority',
header: 'Priority',
filterable: true,
type: 'number',
},
{
accessorKey: 'created',
header: 'Created Date',
filterable: true,
type: 'date',
},
];
function FilterableTable() {
return (
<DataTable
columns={columns}
data={data}
enableColumnFilter
enableGlobalFilter
/>
);
}Expandable Rows with Enhanced Slot System
import { ExpandMoreIcon, ExpandLessIcon } from '@mui/icons-material';
function ExpandableTable() {
const renderSubComponent = (row) => (
<Box p={2}>
<Typography variant="h6">User Details</Typography>
<Grid container spacing={2}>
<Grid item xs={6}>
<Typography><strong>ID:</strong> {row.original.id}</Typography>
<Typography><strong>Email:</strong> {row.original.email}</Typography>
</Grid>
<Grid item xs={6}>
<Typography><strong>Role:</strong> {row.original.role}</Typography>
<Typography><strong>Status:</strong> {row.original.status}</Typography>
</Grid>
</Grid>
</Box>
);
return (
<DataTable
columns={columns}
data={data}
enableExpanding
getRowCanExpand={(row) => row.original.details != null}
renderSubComponent={renderSubComponent}
slotProps={{
expandColumn: {
width: 60,
pinLeft: true,
header: 'Details',
cell: ({ row }) => (
<IconButton
onClick={row.getToggleExpandedHandler()}
size="small"
sx={{
color: 'primary.main',
transition: 'transform 0.2s',
transform: row.getIsExpanded() ? 'rotate(180deg)' : 'rotate(0deg)',
}}
>
{row.getIsExpanded() ? <ExpandLessIcon /> : <ExpandMoreIcon />}
</IconButton>
),
},
}}
/>
);
}Column Management
function ManageableColumnsTable() {
const [columnOrder, setColumnOrder] = useState([]);
const [columnPinning, setColumnPinning] = useState({ left: [], right: [] });
return (
<DataTable
columns={columns}
data={data}
enableColumnVisibility
enableColumnResizing
enableColumnPinning
draggable
onColumnDragEnd={setColumnOrder}
onColumnPinningChange={setColumnPinning}
initialState={{
columnOrder,
columnPinning,
}}
/>
);
}Export with Progress Tracking
function ExportableTable() {
const [exportProgress, setExportProgress] = useState(null);
const handleExportProgress = (progress) => {
setExportProgress(progress);
};
const handleExportComplete = (result) => {
setExportProgress(null);
};
return (
<DataTable
columns={columns}
data={data}
enableExport
exportFilename="users-export"
onExportProgress={handleExportProgress}
onExportComplete={handleExportComplete}
onExportError={(error) => console.error('Export failed:', error)}
/>
);
}🎛️ API Reference
DataTable Component
The main component that renders the data table with all features.
<DataTable<T>
columns={DataTableColumn<T>[]}
data={T[]}
// ... other props
/>Column Definition
Columns are defined using TanStack Table's column definition format with additional properties:
interface DataTableColumn<T> extends ColumnDef<T> {
// Display properties
align?: 'left' | 'center' | 'right';
// Filtering
filterable?: boolean;
type?: 'boolean' | 'number' | 'date' | 'select' | 'text';
options?: { label: string; value: string }[];
// Export
hideInExport?: boolean;
}DataTable API
The DataTable exposes a comprehensive API through refs for programmatic control:
import { useRef } from 'react';
import { DataTable, DataTableApi } from '@ackplus/react-tanstack-data-table';
function MyComponent() {
const tableRef = useRef<DataTableApi<User>>(null);
const handleGetData = () => {
const allData = tableRef.current?.data.getAllData();
};
return (
<DataTable
ref={tableRef}
columns={columns}
data={data}
/>
);
}Available API Methods
Column Management:
columnVisibility.showColumn(columnId)- Show specific columncolumnVisibility.hideColumn(columnId)- Hide specific columncolumnVisibility.toggleColumn(columnId)- Toggle column visibilitycolumnVisibility.showAllColumns()- Show all columnscolumnVisibility.hideAllColumns()- Hide all columnscolumnVisibility.resetColumnVisibility()- Reset to default visibility
Column Ordering:
columnOrdering.setColumnOrder(order)- Set column ordercolumnOrdering.moveColumn(columnId, toIndex)- Move column to positioncolumnOrdering.resetColumnOrder()- Reset to default order
Column Pinning:
columnPinning.pinColumnLeft(columnId)- Pin column to leftcolumnPinning.pinColumnRight(columnId)- Pin column to rightcolumnPinning.unpinColumn(columnId)- Unpin columncolumnPinning.setPinning(pinning)- Set pinning statecolumnPinning.resetColumnPinning()- Reset pinning
Column Resizing:
columnResizing.resizeColumn(columnId, width)- Resize columncolumnResizing.autoSizeColumn(columnId)- Auto-size columncolumnResizing.autoSizeAllColumns()- Auto-size all columnscolumnResizing.resetColumnSizing()- Reset column sizing
Filtering:
filtering.setGlobalFilter(filter)- Set global filterfiltering.clearGlobalFilter()- Clear global filterfiltering.setColumnFilters(filters)- Set column filtersfiltering.addColumnFilter(columnId, operator, value)- Add column filterfiltering.removeColumnFilter(filterId)- Remove column filterfiltering.clearAllFilters()- Clear all filtersfiltering.resetFilters()- Reset all filters
Sorting:
sorting.setSorting(sortingState)- Set sorting statesorting.sortColumn(columnId, direction)- Sort specific columnsorting.clearSorting()- Clear all sortingsorting.resetSorting()- Reset sorting
Pagination:
pagination.goToPage(pageIndex)- Go to specific pagepagination.nextPage()- Go to next pagepagination.previousPage()- Go to previous pagepagination.setPageSize(pageSize)- Set page sizepagination.goToFirstPage()- Go to first pagepagination.goToLastPage()- Go to last page
Selection:
selection.selectRow(rowId)- Select specific rowselection.deselectRow(rowId)- Deselect specific rowselection.toggleRowSelection(rowId)- Toggle row selectionselection.selectAll()- Select all rowsselection.deselectAll()- Deselect all rowsselection.toggleSelectAll()- Toggle select allselection.getSelectionState()- Get current selection stateselection.getSelectedRows()- Get selected rowsselection.getSelectedCount()- Get selected countselection.isRowSelected(rowId)- Check if row is selected
Data Management:
data.refresh()- Refresh datadata.reload()- Reload datadata.getAllData()- Get all datadata.getRowData(rowId)- Get specific row datadata.getRowByIndex(index)- Get row by indexdata.updateRow(rowId, updates)- Update specific rowdata.updateRowByIndex(index, updates)- Update row by indexdata.insertRow(newRow, index?)- Insert new rowdata.deleteRow(rowId)- Delete specific rowdata.deleteRowByIndex(index)- Delete row by indexdata.deleteSelectedRows()- Delete selected rowsdata.replaceAllData(newData)- Replace all datadata.updateMultipleRows(updates)- Update multiple rowsdata.insertMultipleRows(newRows, startIndex?)- Insert multiple rowsdata.deleteMultipleRows(rowIds)- Delete multiple rowsdata.updateField(rowId, fieldName, value)- Update specific fielddata.updateFieldByIndex(index, fieldName, value)- Update field by indexdata.findRows(predicate)- Find rows by predicatedata.findRowIndex(predicate)- Find row index by predicatedata.getDataCount()- Get data countdata.getFilteredDataCount()- Get filtered data count
Layout Management:
layout.resetLayout()- Reset layoutlayout.resetAll()- Reset everythinglayout.saveLayout()- Save current layoutlayout.restoreLayout(layout)- Restore saved layout
Export:
export.exportCSV(options?)- Export to CSVexport.exportExcel(options?)- Export to Excelexport.exportServerData(options)- Server-side exportexport.isExporting()- Check if exportingexport.cancelExport()- Cancel export
Table State:
state.getTableState()- Get current table statestate.getCurrentFilters()- Get current filtersstate.getCurrentSorting()- Get current sortingstate.getCurrentPagination()- Get current paginationstate.getCurrentSelection()- Get current selection
useDataTableApi Hook
Access the table's imperative API:
import { useRef } from 'react';
import { DataTable, DataTableApi } from '@ackplus/react-tanstack-data-table';
function MyComponent() {
const tableRef = useRef<DataTableApi<User>>(null);
const handleGetData = () => {
const allData = tableRef.current?.data.getAllData();
};
return (
<DataTable
ref={tableRef}
columns={columns}
data={data}
/>
);
}🎨 Enhanced Customization with Slots System
The enhanced slot system provides powerful customization capabilities for DataTable components without limitations. This system allows you to override any component with full prop control and proper TypeScript support.
Key Features
- Full Component Customization: Replace any component without limitations
- Intelligent Prop Merging: Special handling for
sx,style, andclassNameprops - Enhanced Type Safety: Better TypeScript inference and proper component prop typing
- Performance Optimized: Efficient prop merging and component creation
- Easy Migration: Works with existing code while providing enhanced capabilities
Basic Slot Customization
import { DataTable } from '@ackplus/react-tanstack-data-table';
import { Star as StarIcon } from '@mui/icons-material';
// Custom icon component
const CustomSearchIcon = (props) => (
<StarIcon {...props} sx={{ color: 'warning.main', ...props.sx }} />
);
function MyTable() {
return (
<DataTable
data={data}
columns={columns}
slots={{
searchIcon: CustomSearchIcon,
}}
slotProps={{
searchIcon: {
fontSize: 'large',
sx: {
animation: 'pulse 2s infinite',
'@keyframes pulse': {
'0%': { transform: 'scale(1)' },
'50%': { transform: 'scale(1.1)' },
'100%': { transform: 'scale(1)' },
},
},
},
}}
/>
);
}Advanced Component Replacement
import { styled, alpha } from '@mui/material/styles';
const CustomToolbar = styled(Box)(({ theme }) => ({
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
padding: theme.spacing(2),
backgroundColor: alpha(theme.palette.primary.main, 0.05),
borderRadius: theme.shape.borderRadius,
}));
const CustomSearchInput = styled('input')(({ theme }) => ({
padding: theme.spacing(1, 2),
border: `1px solid ${theme.palette.divider}`,
borderRadius: theme.shape.borderRadius,
fontSize: theme.typography.body2.fontSize,
'&:focus': {
outline: 'none',
borderColor: theme.palette.primary.main,
boxShadow: `0 0 0 2px ${alpha(theme.palette.primary.main, 0.2)}`,
},
}));
function AdvancedTable() {
return (
<DataTable
data={data}
columns={columns}
slots={{
toolbar: CustomToolbar,
searchInput: ({ value, onChange, placeholder, ...props }) => (
<CustomSearchInput
type="text"
value={value}
onChange={(e) => onChange(e.target.value)}
placeholder={placeholder}
{...props}
/>
),
}}
slotProps={{
toolbar: {
sx: {
background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
color: 'white',
},
},
searchInput: {
placeholder: 'Search anything...',
style: {
minWidth: '300px',
},
},
}}
/>
);
}Complete Customization Example
function FullyCustomizedTable() {
const theme = useTheme();
return (
<DataTable
data={data}
columns={columns}
slots={{
// Custom toolbar with complete styling freedom
toolbar: CustomToolbar,
// Custom search input with full control
searchInput: ({ value, onChange, placeholder, ...props }) => (
<CustomSearchInput
type="text"
value={value}
onChange={(e) => onChange(e.target.value)}
placeholder={placeholder || 'Search anything...'}
{...props}
/>
),
// Custom column visibility control
columnVisibilityControl: (props) => {
const { table, color, ...buttonProps } = props;
return (
<CustomButton
variant="outlined"
startIcon={<VisibilityIcon />}
{...buttonProps}
>
Columns
</CustomButton>
);
},
// Custom export button
exportButton: (props) => {
const { table, color, ...buttonProps } = props;
return (
<CustomButton
variant="contained"
startIcon={<ExportIcon />}
sx={{
background: 'linear-gradient(45deg, #FE6B8B 30%, #FF8E53 90%)',
color: 'white',
...buttonProps.sx
}}
{...buttonProps}
>
Export Data
</CustomButton>
);
},
// Custom table with enhanced styling
table: ({ children, ...props }) => (
<Paper
elevation={3}
sx={{
borderRadius: 2,
overflow: 'hidden',
border: `2px solid ${theme.palette.primary.main}`,
}}
>
<table {...props} style={{ width: '100%' }}>
{children}
</table>
</Paper>
),
// Custom row with hover effects
row: ({ children, row, ...props }) => (
<tr
{...props}
style={{
backgroundColor: row.index % 2 === 0 ? alpha(theme.palette.primary.main, 0.03) : 'transparent',
transition: 'background-color 0.2s ease',
cursor: 'pointer',
...props.style,
}}
onMouseEnter={(e) => {
e.currentTarget.style.backgroundColor = alpha(theme.palette.primary.main, 0.1);
}}
onMouseLeave={(e) => {
e.currentTarget.style.backgroundColor = row.index % 2 === 0 ? alpha(theme.palette.primary.main, 0.03) : 'transparent';
}}
>
{children}
</tr>
),
}}
slotProps={{
// Customize toolbar props
toolbar: {
title: 'Custom Users Table',
subtitle: 'Manage your users with enhanced controls',
sx: {
background: `linear-gradient(135deg, ${alpha(theme.palette.primary.main, 0.1)} 0%, ${alpha(theme.palette.secondary.main, 0.1)} 100%)`,
border: `1px solid ${alpha(theme.palette.primary.main, 0.2)}`,
},
},
// Customize search input
searchInput: {
placeholder: 'Search users by name, email, or role...',
style: {
minWidth: '300px',
fontSize: '14px',
},
},
// Customize column visibility control
columnVisibilityControl: {
title: 'Manage Columns',
menuSx: {
minWidth: 250,
maxHeight: 400,
},
titleSx: {
color: theme.palette.primary.main,
fontWeight: 'bold',
},
checkboxProps: {
color: 'primary',
},
},
// Customize table container
tableContainer: {
sx: {
maxHeight: '600px',
'&::-webkit-scrollbar': {
width: '8px',
},
'&::-webkit-scrollbar-track': {
backgroundColor: alpha(theme.palette.grey[300], 0.5),
borderRadius: '4px',
},
'&::-webkit-scrollbar-thumb': {
backgroundColor: theme.palette.primary.main,
borderRadius: '4px',
'&:hover': {
backgroundColor: theme.palette.primary.dark,
},
},
},
},
// Customize pagination
pagination: {
rowsPerPageOptions: [10, 25, 50, 100, 300, 500, 1000],
sx: {
'& .MuiTablePagination-toolbar': {
backgroundColor: alpha(theme.palette.primary.main, 0.05),
borderTop: `1px solid ${theme.palette.divider}`,
},
'& .MuiTablePagination-selectLabel, & .MuiTablePagination-displayedRows': {
color: theme.palette.primary.main,
fontWeight: 'medium',
},
},
},
}}
/>
);
}Available Slots
Container Slots
root- Main containertableContainer- Table container wrappertable- Table element
Header Slots
toolbar- Main toolbarheader- Table headerheaderRow- Header rowheaderCell- Header cell
Body Slots
body- Table bodyrow- Table rowcell- Table cell
Control Slots
searchInput- Search input componentcolumnVisibilityControl- Column visibility controlcolumnCustomFilterControl- Column filter controlcolumnPinningControl- Column pinning controlexportButton- Export buttonresetButton- Reset buttontableSizeControl- Table size controlbulkActionsToolbar- Bulk actions toolbar
Icon Slots
searchIcon- Search iconfilterIcon- Filter iconexportIcon- Export iconcolumnIcon- Column visibility iconresetIcon- Reset iconpinIcon- Pin column iconunpinIcon- Unpin column iconcsvIcon- CSV export iconexcelIcon- Excel export iconviewComfortableIcon- Comfortable view iconviewCompactIcon- Compact view icon
Special Slots
loadingRow- Loading state rowemptyRow- Empty state rowfooter- Table footerpagination- Pagination component
Best Practices
1. Component Composition
// Good: Compose components properly
const CustomControl = ({ children, ...props }) => (
<Box sx={{ display: 'flex', gap: 1 }} {...props}>
{children}
</Box>
);
// Usage
slots={{
toolbar: ({ children, ...props }) => (
<CustomControl {...props}>
{children}
</CustomControl>
),
}}2. Prop Forwarding
// Good: Always forward props
const CustomIcon = (props) => (
<StarIcon {...props} sx={{ color: 'primary.main', ...props.sx }} />
);
// Bad: Not forwarding props
const CustomIcon = () => <StarIcon color="primary" />;3. TypeScript Support
// Good: Use proper typing
interface CustomButtonProps {
onClick?: () => void;
children: React.ReactNode;
[key: string]: any; // Allow additional props
}
const CustomButton: React.FC<CustomButtonProps> = ({ children, ...props }) => (
<Button {...props}>{children}</Button>
);4. Performance Considerations
// Good: Memoize expensive components
const CustomToolbar = React.memo(({ children, ...props }) => (
<Box {...props}>{children}</Box>
));
// Good: Use callbacks for event handlers
const handleClick = useCallback(() => {
// Handle click
}, []);Migration from Basic Slots
// Before
<DataTable
slots={{
searchIcon: MyIcon,
}}
slotProps={{
searchIcon: { color: 'primary' },
}}
/>
// After (Enhanced)
<DataTable
slots={{
searchIcon: MyIcon,
}}
slotProps={{
searchIcon: {
color: 'primary',
sx: { fontSize: 20 }, // Now supports sx prop merging
},
}}
/>Logging & Debugging
Use the built-in logger to trace pagination, server calls, and state transitions without sprinkling console.log statements throughout your app.
import { DataTable, configureDataTableLogging } from '@ackplus/react-tanstack-data-table';
configureDataTableLogging({
enabled: true,
level: 'debug',
includeTimestamp: true,
});
<DataTable
columns={columns}
data={rows}
logging={{
enabled: true,
level: 'info',
prefix: 'OrdersTable',
}}
/>- Call
configureDataTableLoggingonce (for example in your app bootstrap) to set global defaults. - Use the
loggingprop to override settings per table or disable instrumentation for specific instances. - When
loggingis omitted, instances inherit the global configuration.
Troubleshooting
Common Issues
Props not merging correctly
- Ensure you're using the enhanced slot system
- Check prop priority order (user > slot > default)
TypeScript errors
- Use
[key: string]: anyfor flexible prop interfaces - Ensure proper prop forwarding with spread operator
- Filter out incompatible props like
tableandcolorfor Button components
- Use
Styling conflicts
- Check sx prop merging order
- Use proper CSS specificity
Performance issues
- Memoize expensive components
- Use callbacks for event handlers
- Avoid inline function definitions
The enhanced slot system provides unprecedented flexibility for customizing DataTable components. With proper prop merging, full TypeScript support, and intelligent component composition, you can create highly customized tables without limitations.
🔧 Migration Guide
From v0.x to v1.x
Key changes in v1.0:
- Updated to latest TanStack Table v8
- Improved TypeScript support
- Enhanced slot system
- Better server-side integration
🤝 Contributing
We welcome contributions! Please see our Contributing Guide for details.
💖 Support the Project
If you find this package helpful and want to support its development, consider making a donation:
Your support helps us:
- 🛠️ Maintain and improve the library
- 🐛 Fix bugs and add new features
- 📚 Create better documentation
- 🚀 Keep the project active and up-to-date
📄 License
MIT © ACK Solutions
🆘 Support
- 🚀 Live Demo - Interactive examples and playground
- 📖 Documentation
- 🐛 Issue Tracker
- 💬 Discussions
If you find this package helpful, please consider giving it a ⭐ on GitHub!
