A powerful React data table component built with MUI and TanStack Table
npm install @ackplus/react-tanstack-data-tableA 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.
Experience all the features in action with our interactive demo showcasing advanced table functionality, filtering, sorting, pagination, and more.
- 🚀 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
``bash`
npm install @ackplus/react-tanstack-data-table
`bash`
yarn add @ackplus/react-tanstack-data-table
`bash`
pnpm add @ackplus/react-tanstack-data-table
Make sure you have the following peer dependencies installed:
`bash`
npm install @emotion/react @emotion/styled @mui/icons-material @mui/material @tanstack/react-table @tanstack/react-virtual react react-dom
`tsx
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
const columns = [
columnHelper.accessor('name', {
header: 'Name',
size: 150,
}),
columnHelper.accessor('email', {
header: 'Email',
size: 200,
}),
columnHelper.accessor('status', {
header: 'Status',
cell: ({ getValue }) => (
color={getValue() === 'active' ? 'success' : 'default'}
/>
),
}),
columnHelper.accessor('role', {
header: 'Role',
size: 120,
}),
];
const data: User[] = [
{ id: 1, name: 'John Doe', email: 'john@example.com', status: 'active', role: 'Admin' },
{ id: 2, name: 'Jane Smith', email: 'jane@example.com', status: 'inactive', role: 'User' },
// ... more data
];
function MyDataTable() {
return (
data={data}
enableSorting
enableGlobalFilter
enablePagination
enableRowSelection
enableColumnVisibility
enableExport
/>
);
}
`
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| columns | DataTableColumn | 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 |
| 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 |
| 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 |
The SelectionState interface provides detailed information about the current selection:
`typescript`
interface SelectionState {
ids: string[]; // Array of selected/excluded row IDs
type: 'include' | 'exclude'; // Selection mode
}
- Include mode: ids contains the selected row IDsids
- Exclude mode: contains the excluded row IDs (all others are selected)
This allows for efficient handling of large datasets where you might select "all except these few".
| 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 |
| 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 |
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| enableSorting | boolean | true | Enable column sorting |sortingMode
| | 'client' \| 'server' | 'client' | Sorting mode |onSortingChange
| | (sorting) => void | - | Sorting change callback |
| 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 |
| 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 | - | Server-side export handler |onExportCancel
| | () => void | - | Export cancellation callback |
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).
| 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 |
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| enableVirtualization | boolean | false | Enable row virtualization |estimateRowHeight
| | number | 52 | Estimated row height for virtualization |
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| slots | Partial | {} | Custom component slots |slotProps
| | PartialSlotProps | {} | Props for slot components |initialState
| | Partial | {} | Initial table state |skeletonRows
| | number | 5 | Number of skeleton rows for loading state |footerFilter
| | ReactNode | - | Additional filter components in footer |
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:
`tsx`
columns={columns}
enableRowSelection
enableMultiRowSelection
slotProps={{
selectionColumn: {
width: 80,
pinLeft: true,
id: 'custom-selection',
// Custom column configuration
header: ({ table }) => (
indeterminate={table.getIsSomeRowsSelected()}
onChange={() => table.toggleAllRowsSelected()}
sx={{ color: 'primary.main' }}
/>
),
cell: ({ row, table }) => (
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:
`tsx`
columns={columns}
enableExpanding
getRowCanExpand={(row) => row.original.details != null}
renderSubComponent={(row) => (
{JSON.stringify(row.original.details, null, 2)}
)}
slotProps={{
expandColumn: {
width: 60,
pinLeft: true,
id: 'custom-expand',
// Custom column configuration
header: 'Expand',
cell: ({ row }) => (
size="small"
sx={{ color: 'primary.main' }}
>
{row.getIsExpanded() ?
),
},
}}
/>
#### Advanced Special Column Customization
You can completely replace the special column components using the slots system:
`tsx
import { createSelectionColumn, createExpandingColumn } from '@ackplus/react-tanstack-data-table';
function CustomTable() {
// Create custom selection column
const customSelectionColumn = createSelectionColumn({
width: 100,
pinLeft: true,
header: ({ table }) => (
indeterminate={table.getIsSomeRowsSelected()}
onChange={() => table.toggleAllRowsSelected()}
sx={{
color: 'primary.main',
'&.Mui-checked': { color: 'primary.main' }
}}
/>
),
cell: ({ row, table }) => (
onChange={() => table.toggleRowSelected(row.id)}
sx={{
color: 'secondary.main',
'&.Mui-checked': { color: 'secondary.main' }
}}
/>
),
});
// Create custom expanding column
const customExpandingColumn = createExpandingColumn({
width: 80,
pinLeft: true,
header: 'Details',
cell: ({ row }) => (
size="small"
sx={{
color: 'primary.main',
transition: 'transform 0.2s',
transform: row.getIsExpanded() ? 'rotate(180deg)' : 'rotate(0deg)',
}}
>
),
});
return (
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.
`tsx
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 }) => (
indeterminate={table.getIsSomeRowsSelected()}
onChange={() => table.toggleAllRowsSelected()}
sx={{ color: 'primary.main' }}
/>
),
cell: ({ row, table }) => (
onChange={() => table.toggleRowSelected(row.id)}
sx={{ color: 'secondary.main' }}
/>
),
});
// Create a custom expanding column
const customExpandingColumn = createExpandingColumn({
width: 80,
pinLeft: true,
header: 'Details',
cell: ({ row }) => (
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',
},
}}
>
),
});
// Use in your table
data={data}
enableRowSelection
enableExpanding
// ... other props
/>
`
`tsx
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 (
dataMode="server"
loading={loading}
onFetchData={fetchData}
enablePagination
enableSorting
enableGlobalFilter
paginationMode="server"
sortingMode="server"
filterMode="server"
/>
);
}
`
`tsx
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 (
variant="contained"
color="error"
onClick={() => deleteUsers(selectedRows)}
>
Delete ({selectedCount})
variant="outlined"
onClick={() => exportUsers(selectedRows)}
>
Export Selected
);
};
return (
data={data}
enableRowSelection
enableMultiRowSelection
enableBulkActions
bulkActions={bulkActions}
onSelectionChange={setSelectedUsers}
slotProps={{
selectionColumn: {
width: 80,
pinLeft: true,
header: ({ table }) => (
indeterminate={table.getIsSomeRowsSelected()}
onChange={() => table.toggleAllRowsSelected()}
sx={{
color: 'primary.main',
'&.Mui-checked': { color: 'primary.main' }
}}
/>
),
cell: ({ row, table }) => (
onChange={() => table.toggleRowSelected(row.id)}
sx={{
color: 'secondary.main',
'&.Mui-checked': { color: 'secondary.main' }
}}
/>
),
},
}}
/>
);
}
`
`tsx
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 (
data={data}
enableColumnFilter
enableGlobalFilter
/>
);
}
`
`tsx
import { ExpandMoreIcon, ExpandLessIcon } from '@mui/icons-material';
function ExpandableTable() {
const renderSubComponent = (row) => (
);
return (
data={data}
enableExpanding
getRowCanExpand={(row) => row.original.details != null}
renderSubComponent={renderSubComponent}
slotProps={{
expandColumn: {
width: 60,
pinLeft: true,
header: 'Details',
cell: ({ row }) => (
size="small"
sx={{
color: 'primary.main',
transition: 'transform 0.2s',
transform: row.getIsExpanded() ? 'rotate(180deg)' : 'rotate(0deg)',
}}
>
{row.getIsExpanded() ?
),
},
}}
/>
);
}
`
`tsx
function ManageableColumnsTable() {
const [columnOrder, setColumnOrder] = useState([]);
const [columnPinning, setColumnPinning] = useState({ left: [], right: [] });
return (
data={data}
enableColumnVisibility
enableColumnResizing
enableColumnPinning
draggable
onColumnDragEnd={setColumnOrder}
onColumnPinningChange={setColumnPinning}
initialState={{
columnOrder,
columnPinning,
}}
/>
);
}
`
`tsx
function ExportableTable() {
const [exportProgress, setExportProgress] = useState(null);
const handleExportProgress = (progress) => {
setExportProgress(progress);
};
const handleExportComplete = (result) => {
setExportProgress(null);
};
return (
data={data}
enableExport
exportFilename="users-export"
onExportProgress={handleExportProgress}
onExportComplete={handleExportComplete}
onExportError={(error) => console.error('Export failed:', error)}
/>
);
}
`
The main component that renders the data table with all features.
`tsx`
columns={DataTableColumn
data={T[]}
// ... other props
/>
Columns are defined using TanStack Table's column definition format with additional properties:
`tsx`
interface DataTableColumn
// Display properties
align?: 'left' | 'center' | 'right';
// Filtering
filterable?: boolean;
type?: 'boolean' | 'number' | 'date' | 'select' | 'text';
options?: { label: string; value: string }[];
// Export
hideInExport?: boolean;
}
The DataTable exposes a comprehensive API through refs for programmatic control:
`tsx
import { useRef } from 'react';
import { DataTable, DataTableApi } from '@ackplus/react-tanstack-data-table';
function MyComponent() {
const tableRef = useRef
const handleGetData = () => {
const allData = tableRef.current?.data.getAllData();
};
return (
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
Access the table's imperative API:
`tsx
import { useRef } from 'react';
import { DataTable, DataTableApi } from '@ackplus/react-tanstack-data-table';
function MyComponent() {
const tableRef = useRef
const handleGetData = () => {
const allData = tableRef.current?.data.getAllData();
};
return (
columns={columns}
data={data}
/>
);
}
`
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.
- Full Component Customization: Replace any component without limitations
- Intelligent Prop Merging: Special handling for sx, style, and className props
- 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
`tsx
import { DataTable } from '@ackplus/react-tanstack-data-table';
import { Star as StarIcon } from '@mui/icons-material';
// Custom icon component
const CustomSearchIcon = (props) => (
);
function MyTable() {
return (
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)' },
},
},
},
}}
/>
);
}
`
`tsx
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},0 0 0 2px ${alpha(theme.palette.primary.main, 0.2)}
borderRadius: theme.shape.borderRadius,
fontSize: theme.typography.body2.fontSize,
'&:focus': {
outline: 'none',
borderColor: theme.palette.primary.main,
boxShadow: ,
},
}));
function AdvancedTable() {
return (
columns={columns}
slots={{
toolbar: CustomToolbar,
searchInput: ({ value, onChange, placeholder, ...props }) => (
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',
},
},
}}
/>
);
}
`
`tsx
function FullyCustomizedTable() {
const theme = useTheme();
return (
columns={columns}
slots={{
// Custom toolbar with complete styling freedom
toolbar: CustomToolbar,
// Custom search input with full control
searchInput: ({ value, onChange, placeholder, ...props }) => (
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 (
startIcon={
{...buttonProps}
>
Columns
);
},
// Custom export button
exportButton: (props) => {
const { table, color, ...buttonProps } = props;
return (
startIcon={
sx={{
background: 'linear-gradient(45deg, #FE6B8B 30%, #FF8E53 90%)',
color: 'white',
...buttonProps.sx
}}
{...buttonProps}
>
Export Data
);
},
// Custom table with enhanced styling
table: ({ children, ...props }) => (
sx={{
borderRadius: 2,
overflow: 'hidden',
border: 2px solid ${theme.palette.primary.main},linear-gradient(135deg, ${alpha(theme.palette.primary.main, 0.1)} 0%, ${alpha(theme.palette.secondary.main, 0.1)} 100%)
}}
>
{children}
),
// Custom row with hover effects
row: ({ children, row, ...props }) => (
{...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}
),
}}
slotProps={{
// Customize toolbar props
toolbar: {
title: 'Custom Users Table',
subtitle: 'Manage your users with enhanced controls',
sx: {
background: ,1px solid ${alpha(theme.palette.primary.main, 0.2)}
border: ,1px solid ${theme.palette.divider}
},
},
// 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: ,`
},
'& .MuiTablePagination-selectLabel, & .MuiTablePagination-displayedRows': {
color: theme.palette.primary.main,
fontWeight: 'medium',
},
},
},
}}
/>
);
}
#### 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
#### 1. Component Composition
`tsx
// Good: Compose components properly
const CustomControl = ({ children, ...props }) => (
{children}
);
// Usage
slots={{
toolbar: ({ children, ...props }) => (
{children}
),
}}
`
#### 2. Prop Forwarding
`tsx
// Good: Always forward props
const CustomIcon = (props) => (
);
// Bad: Not forwarding props
const CustomIcon = () =>
`
#### 3. TypeScript Support
`tsx
// Good: Use proper typing
interface CustomButtonProps {
onClick?: () => void;
children: React.ReactNode;
[key: string]: any; // Allow additional props
}
const CustomButton: React.FC
);
`
#### 4. Performance Considerations
`tsx
// Good: Memoize expensive components
const CustomToolbar = React.memo(({ children, ...props }) => (
));
// Good: Use callbacks for event handlers
const handleClick = useCallback(() => {
// Handle click
}, []);
`
`tsx
// Before
searchIcon: MyIcon,
}}
slotProps={{
searchIcon: { color: 'primary' },
}}
/>
// After (Enhanced)
searchIcon: MyIcon,
}}
slotProps={{
searchIcon: {
color: 'primary',
sx: { fontSize: 20 }, // Now supports sx prop merging
},
}}
/>
`
Use the built-in logger to trace pagination, server calls, and state transitions without sprinkling console.log statements throughout your app.
`tsx
import { DataTable, configureDataTableLogging } from '@ackplus/react-tanstack-data-table';
configureDataTableLogging({
enabled: true,
level: 'debug',
includeTimestamp: true,
});
data={rows}
logging={{
enabled: true,
level: 'info',
prefix: 'OrdersTable',
}}
/>
`
- Call configureDataTableLogging once (for example in your app bootstrap) to set global defaults.logging
- Use the prop to override settings per table or disable instrumentation for specific instances.logging
- When is omitted, instances inherit the global configuration.
#### Common Issues
1. Props not merging correctly
- Ensure you're using the enhanced slot system
- Check prop priority order (user > slot > default)
2. TypeScript errors
- Use [key: string]: any for flexible prop interfacestable
- Ensure proper prop forwarding with spread operator
- Filter out incompatible props like and color` for Button components
3. Styling conflicts
- Check sx prop merging order
- Use proper CSS specificity
4. 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.
Key changes in v1.0:
- Updated to latest TanStack Table v8
- Improved TypeScript support
- Enhanced slot system
- Better server-side integration
We welcome contributions! Please see our Contributing Guide for details.
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
MIT © ACK Solutions
- 🚀 Live Demo - Interactive examples and playground
- 📖 Documentation
- 🐛 Issue Tracker
- 💬 Discussions
If you find this package helpful, please consider giving it a ⭐ on GitHub!