A powerful and flexible React data grid component built on top of Material React Table, providing advanced features for data visualization, filtering, sorting, pagination, and row selection.
npm install @insticc/react-datagrid-2A powerful and flexible React data grid component built on top of Material React Table, providing advanced features for data visualization, filtering, sorting, pagination, and row selection.
- Installation
- Basic Usage
- Props Reference
- Core Props
- Column Configuration
- Actions & Toolbar
- Export Options
- Selection & Interaction
- Pagination & Display
- Styling & Layout
- Advanced Features
- Cache & Updates
- Callbacks
- Column Types
- Examples
- API Reference
- Performance Tips
- Browser Support
- Troubleshooting
---
``bash`
npm install @insticc/react-datagrid-2
`bash`
npm install react prop-types material-react-table semantic-ui-react @mui/material @mui/x-date-pickers date-fns bootstrap semantic-ui-css
---
`jsx
import React, { useState } from 'react';
import { DataGrid } from '@insticc/react-datagrid-2';
function MyComponent() {
const [selectedRows, setSelectedRows] = useState([]);
const columns = [
{ accessorKey: 'id', header: 'ID', type: 'text' },
{ accessorKey: 'name', header: 'Name', type: 'text' },
{ accessorKey: 'email', header: 'Email', type: 'email' },
{ accessorKey: 'createdAt', header: 'Created', type: 'date', isDateColumn: true },
];
const data = [
{ id: '1', name: 'John Doe', email: 'john@example.com', createdAt: '2025-01-15' },
{ id: '2', name: 'Jane Smith', email: 'jane@example.com', createdAt: '2025-02-20' },
];
return (
createRows={data}
rowKey="id"
selectData={setSelectedRows}
hasExcelExport={true}
hasPdfExport={true}
/>
);
}
`
---
#### columns (required)Array
- Type: `
- Description: Array of column definitions that determine how data is displayed
- Example:jsx`
const columns = [
{
accessorKey: 'name', // Key to access data (use with accessorFn or alone)
header: 'Full Name', // Column header text
type: 'text', // Cell type - formatter applied automatically
// Data Access
accessorFn: (row) => row.firstName + ' ' + row.lastName,
// Filtering & Sorting
enableSorting: true, // Enable/disable sorting (default: true)
enableColumnFilter: true, // Enable/disable filtering (default: true)
enableColumnFilterModes: true, // Allow changing filter modes (default: true)
filterFn: 'contains', // Filter function type (default: 'contains')
sortingFn: 'basic', // Sorting function (default: 'basic' or custom for dates)
isDateColumn: false, // Special handling for dates (default: false)
// Display
cellClass: 'custom-class', // CSS class wrapping cell content
Cell: CustomComponent, // Optional: Custom cell renderer (receives typeValue)
enableResizing: true, // Allow column resizing (default: true)
grow: true, // Column can grow (default: true)
enableClickToCopy: false, // Enable click-to-copy (default: false)
enableColumnActions: false, // Show column actions menu (default: false)
}
];
Column Rendering Modes:
- type only: Formatter applied automaticallytype
- + cellClass: Formatted content wrapped in div with CSS classtype
- + Cell: Custom component receives typeValue (formatted content) as propCell
- only: Full custom rendering without type formatter
#### createRows (required)Array
- Type:
#### rowKey (required)string
- Type: rowKey="id"
- Description: Property name used as unique identifier for each row
- Example: or rowKey="uuid"
#### selectData (required)function
- Type: (selectedRows: Array
- Description: Callback function that receives selected rows whenever selection changes
- Signature:
`
---
#### Understanding accessorKey vs accessorFn
The DataGrid provides two ways to access data from your rows:
##### accessorKey (Simple Access)string
- Type: `
- Use when: You want to access a property directly from the row object
- Example:jsx`
{
accessorKey: 'name', // Accesses row.name
header: 'Name'
}
##### accessorFn (Custom Access)(row: Object) => any
- Type: accessorKey
- Use when: You need to compute or transform the value from row data
- Receives: The complete row object as parameter
- Returns: The value to be used for display, filtering, and sorting
- Priority: Overrides if both are defined
- Examples:
`jsx
// Example 1: Handle null/undefined values with fallback
{
accessorKey: 'acronym',
accessorFn: (row) => row.acronym ?? '',
header: 'Acronym',
type: 'text'
}
// Example 2: Access nested object properties
{
accessorKey: 'paperCount',
accessorFn: (row) => row.numberPapers?.value ?? 0,
header: 'Papers',
type: 'integer'
}
// Example 3: Combine multiple fields
{
accessorKey: 'fullName',
accessorFn: (row) => ${row.firstName} ${row.lastName},
header: 'Full Name',
type: 'text'
}
// Example 4: Conditional logic
{
accessorKey: 'status',
accessorFn: (row) => row.isActive ? 'Active' : 'Inactive',
header: 'Status',
type: 'text'
}
// Example 5: Complex calculations
{
accessorKey: 'total',
accessorFn: (row) => (row.price || 0) * (row.quantity || 0),
header: 'Total',
type: 'currency'
}
// Example 6: Array to string conversion
{
accessorKey: 'tags',
accessorFn: (row) => row.tags?.join(', ') ?? 'No tags',
header: 'Tags',
type: 'text'
}
// Example 7: Date formatting for sorting
{
accessorKey: 'createdDate',
accessorFn: (row) => row.createdAt ? new Date(row.createdAt).getTime() : 0,
header: 'Created',
type: 'date',
isDateColumn: true
}
`
Important Notes:
- accessorFn is executed for every cell render, filter, and sort operationaccessorFn
- Keep the function lightweight to avoid performance issues
- The returned value is what gets filtered and sorted (not the original cell display)
- When using , you typically still need accessorKey as a unique identifier for the columnaccessorFn
- value is passed to the type formatter (if type is specified)
Performance Tip:
`jsx
// Bad - Creates new object every time
accessorFn: (row) => ({ value: row.data, label: row.name })
// Good - Returns simple value
accessorFn: (row) => row.data?.value ?? 0
`
#### columnVisibilityStateobject
- Type: {}
- Default: `
- Description: Controls which columns are visible/hidden
- Example:jsx`
columnVisibilityState={{
email: false, // Hide email column
phone: true, // Show phone column
id: false // Hide ID column
}}
#### columnOrderArray
- Type: []
- Default: `
- Description: Defines the order of columns by their accessorKey
- Example:jsx`
columnOrder={['name', 'email', 'createdAt', 'id']}
---
#### actionsArray
- Type: null
- Default: name
- Description: Array of custom action buttons displayed in the toolbar
- Action Object Properties:
- (string): Button labelfunction
- (function, required): Callback when button is clicked - receives selected rows or table instancetooltip
- (string): Tooltip text on hovercolor
- (string): Button color - one of: 'blue', 'red', 'green', 'yellow', 'orange', 'black', 'grey', 'teal', 'brown', 'violet', 'purple', 'olive', 'pink'icon
- (string|element): Icon name (Semantic UI) or React elementselectionMode
- (string): When button is enabled:'single'
- - Enabled only when exactly one row is selected'multi'
- - Enabled when one or more rows are selected'always'
- - Always enabled regardless of selectionconfirmMessage
- (string|element): Confirmation message before action executeshasConfirmMessage
- (boolean): Whether to show confirmation dialogdisabled
- (boolean): Manually disable the buttonvisible
- (boolean): Show/hide the button (default: true)toggle
- (boolean): Render as toggle buttonactive
- (boolean): Toggle button active state (when toggle: true)key
- (string): Unique React key (defaults to name)`
- Example:jsx`
actions={[
{
name: 'Delete',
function: (selectedRows) => handleDelete(selectedRows),
tooltip: 'Delete selected rows',
color: 'red',
icon: 'trash',
selectionMode: 'multi',
hasConfirmMessage: true,
confirmMessage: 'Are you sure you want to delete these rows?'
},
{
name: 'Edit',
function: (selectedRows) => handleEdit(selectedRows[0]),
tooltip: 'Edit selected row',
color: 'blue',
icon: 'edit',
selectionMode: 'single'
},
{
name: 'Add New',
function: () => handleAdd(),
tooltip: 'Add new record',
color: 'green',
icon: 'plus',
selectionMode: 'always'
},
{
name: 'Archive Mode',
function: () => toggleArchiveMode(),
tooltip: 'Toggle archive view',
color: 'grey',
icon: 'archive',
toggle: true,
active: isArchiveMode,
selectionMode: 'always'
}
]}
#### filterActionsArray
- Type: null
- Default: name
- Description: Array of toggle filter action buttons displayed in the toolbar for showing/hiding data based on filters
- Filter Action Object Properties:
- (string): Button labelfunction
- (function, required): Callback when button is toggled - receives current statestate
- (boolean): Current filter state (true = filter active/hidden, false = filter inactive/shown)key
- (string): Unique React key (defaults to name)tooltip
- (string): Tooltip text on hoverdisabled
- (boolean): Manually disable the buttonvisible
- (boolean): Show/hide the button (default: true)state=true
- Button Appearance:
- When : Orange color with eye-slash icon (items hidden)state=false
- When : Green color with eye icon (items shown)`
- Example:jsx
const [hideCompleted, setHideCompleted] = useState(false);
const [hideArchived, setHideArchived] = useState(true);
filterActions={[
{
name: 'Completed',
state: hideCompleted,
function: () => setHideCompleted(!hideCompleted),
tooltip: 'Toggle completed items visibility',
key: 'filter-completed'
},
{
name: 'Archived',
state: hideArchived,
function: () => setHideArchived(!hideArchived),
tooltip: 'Toggle archived items visibility',
disabled: false,
visible: true
},
{
// Dynamic button text based on state
state: hideEvents,
name: hideEvents ? "Hiding Events" : "Showing Events",
tooltip: hideEvents ? "Show Events" : "Hide Events",
function: () => setHideEvents(!hideEvents),
visible: !!handleHideEvents, // Only show if handler exists
}
]}
`
#### extraActionsArray
- Type: null
- Default: function
- Description: Additional custom action buttons displayed on the right side of the toolbar
- Extra Action Object Properties:
- (function, required): Callback when button is clickedcontent
- (string|element, required): Button content/labeltooltip
- (string): Tooltip text on hovericon
- (string|element): Icon name or React elementstyle
- (object): Custom CSS styles for the buttonpropsButton
- (object): Additional props passed to Semantic UI Button component`
- Example:jsx`
extraActions={[
{
function: () => openSettings(),
content: 'Settings',
tooltip: 'Open settings',
icon: 'setting',
style: { backgroundColor: '#f0f0f0' }
},
{
function: () => downloadReport(),
content: 'Download',
tooltip: 'Download report',
icon: 'download',
propsButton: { loading: isDownloading }
}
]}
#### enableTopToolbarboolean
- Type: true
- Default:
- Description: Show/hide the top toolbar containing actions and pagination
#### enableBottomToolbarboolean
- Type: false
- Default:
- Description: Show/hide the bottom toolbar
#### hasClearFiltersBtnboolean
- Type: true
- Default:
- Description: Show/hide the "Clear Filters" button in toolbar
#### hasClearSelectionBtnboolean
- Type: true
- Default: disableSelect={false}
- Description: Show/hide the "Clear Selection" button in toolbar
- Note: Only visible when or disableRows array has items
#### disableAllActionsboolean
- Type: false
- Default:
- Description: Hide all action buttons in the top toolbar
#### disableSideActionsboolean
- Type: false
- Default:
- Description: Hide side action buttons (export, cache, clear filters, help) while keeping main actions visible
#### gridHelperobject | null
- Type: null
- Default: title
- Description: Adds a help button with custom content in a modal dialog
- Required Properties (if defined):
- (string|element, required): Help dialog titlecontent
- (string|element, required): Help dialog content`
- Example:jsx`
gridHelper={{
title: 'Grid Instructions',
content: (
How to use this grid:
)
}}
---
#### hasExcelExportboolean
- Type: false
- Default:
- Description: Enable Excel export button in the toolbar
#### hasPdfExportboolean
- Type: false
- Default:
- Description: Enable PDF export button in the toolbar
Export Behavior:
- Both export buttons are rendered by the ExportActions component
- Exports respect current filters and column visibility
- Selected rows can be exported if selection is enabled
- Export filename is auto-generated or can be customized
---
#### disableSelectboolean
- Type: false
- Default:
- Description: Completely disable row selection checkboxes and click-to-select behavior
#### enableMultiRowSelectionboolean
- Type: true
- Default: true
- Description: Allow selecting multiple rows at once
- Behavior:
- - Users can select multiple rows using checkboxes or Shift+Clickfalse
- - Only one row can be selected at a time
#### selectAllModestring
- Type: 'page'
- Default: 'page'
- Options: , 'all''page'
- Description:
- - "Select All" checkbox selects only rows on current page'all'
- - "Select All" checkbox selects all filtered rows across all pages
#### selectedIdsArray
- Type: []
- Default: `
- Description: Array of row IDs that should be pre-selected when grid loads
- Example:jsx`
selectedIds={[1, 5, 10]} // Pre-select rows with these IDs
- Note: Component syncs automatically when this prop changes
#### disableRowsArray
- Type: []
- Default: rowKey
- Description: Array of row IDs (based on ) that should be disabled and cannot be selected`
- Example:jsx`
disableRows={[3, 7, 9]} // Disable selection for these row IDs#e3e3e3
- Visual: Disabled rows are shown with gray background ()
#### hasSubRowsboolean
- Type: false
- Default: subRows
- Description: Enable support for hierarchical/nested rows
- Requirements: Data must include property for parent rows`
- Example Data:jsx`
const data = [
{
id: 1,
name: 'Parent Row',
subRows: [
{ id: '1.1', name: 'Child Row 1' },
{ id: '1.2', name: 'Child Row 2' }
]
}
];
#### enableExpandingboolean
- Type: false
- Default: hasSubRows={true}
- Description: Show expand/collapse icons for rows with subRows
- Requires:
---
#### enablePaginationboolean
- Type: true
- Default:
- Description: Enable/disable pagination controls
#### paginationstring
- Type: 'both'
- Default: 'top'
- Options: , 'bottom', 'both''top'
- Description: Position of pagination controls
- Note: When using , pagination is integrated into the top toolbar
#### pageSizenumber
- Type: 150
- Default:
- Description: Number of rows displayed per page initially
#### itemsPerPageArray
- Type: [50, 100, 150]
- Default: `
- Description: Options available in the rows-per-page dropdown
- Example:jsx`
itemsPerPage={[10, 25, 50, 100, 200]}
---
#### rowHeightnumber
- Type: 75
- Default:
- Description: Minimum height of each row in pixels
#### fontSizenumber
- Type: 14
- Default: enableCompactStyleMode={true}
- Description: Base font size for grid content in pixels
- Compact Mode: When , responsive sizing is used: clamp(fontSize-3px, 1.1vw, fontSize)
#### gridHeightnumber | string
- Type: 600
- Default: `
- Description: Maximum height of the grid container
- Examples:jsx`
gridHeight={600} // 600px fixed height
gridHeight="80vh" // 80% of viewport height
gridHeight="calc(100vh - 200px)" // Dynamic height calculation
#### enableCompactStyleModeboolean
- Type: false
- Default:
- Description: Enable compact styling with reduced padding and responsive font sizes
- Features:
- Reduced cell padding (2px vs auto)
- Responsive font sizing using CSS clamp()
- Tighter filter input heights (17px vs default)
- Reduced column header spacing
- Optimized for displaying dense data
#### getRowStylefunction
- Type: ({ row }) => object
- Description: Custom function to apply conditional styles to rows based on data
- Signature: `
- Example:jsx`
getRowStyle={({ row }) => {
const styles = {};
if (row.original.status === 'active') {
styles.backgroundColor = '#e8f5e9';
}
if (row.original.priority === 'high') {
styles.color = 'red';
styles.fontWeight = 'bold';
}
if (row.original.isExpired) {
styles.opacity = 0.6;
styles.textDecoration = 'line-through';
}
return styles;
}}
#### enableFixedHeaderboolean
- Type: true
- Default: grid-sticky-header
- Description: Pin column headers to top when scrolling vertically
- Implementation: Uses CSS sticky positioning with class
#### enableFixedActionsboolean
- Type: false
- Default: enableFixedHeader={true}
- Description: Pin action toolbar to top when scrolling
- Requires: grid-sticky-actions
- Implementation: Uses CSS sticky positioning with class
---
#### enableGlobalFilterboolean
- Type: false
- Default:
- Description: Show global search input that filters across all columns
#### globalFilterFnstring
- Type: 'contains'
- Default: 'contains'
- Options: , 'fuzzy', 'between', 'equals', 'greaterThan', 'lessThan', 'notEquals', 'lessThanOrEqualTo', 'greaterThanOrEqualTo', 'empty', 'notEmpty', 'startsWith', 'endsWith', 'betweenInclusive'
- Description: Filter function used for global search
#### enableColumnFilterModesboolean
- Type: true
- Default: ColumnFilter
- Description: Allow users to change filter type per column (contains, equals, regex, etc.)
- Available Modes: Rendered through component
#### enableVirtualizationboolean
- Type: false
- Default: overscan: 5
- Description: Enable row and column virtualization for large datasets
- Recommended: For grids with 1000+ rows
- Configuration:
- Row virtualizer: overscan: columns.length
- Column virtualizer:
- Scroll-to-top on sort change
#### enableFullScreenToggleboolean
- Type: false
- Default:
- Description: Show fullscreen toggle button in toolbar
#### enableDensityToggleboolean
- Type: false
- Default:
- Description: Show density toggle button (compact/comfortable/spacious)
---
#### updateCachefunction
- Type: undefined
- Default: () => void
- Description: Callback function triggered when cache update button is clicked
- Signature: `
- Example:jsx`
updateCache={() => {
fetchLatestData();
}}
- Note: Cache button only appears when this prop is provided
#### cacheUpdateTextstring
- Type: undefined
- Default: "Refresh data from server"
- Description: Tooltip text displayed on hover over the cache update button
- Example:
#### cacheUpdatingboolean
- Type: false
- Default: true
- Description: Shows loading state on cache update button
- Visual: Changes button icon to loading spinner
- Disables: Button is disabled while
---
#### onVisibleRowsChangefunction
- Type: (visibleRows: Array
- Description: Called whenever the visible rows change (filtering, sorting, pagination)
- Signature:
---
The DataGrid supports various pre-built cell types via the type property in column definitions. These formatters are automatically applied without requiring custom cell components.
- Plain text display - Bold text (font-weight: bold) - Gray text (#666666) - Small font size text - Date only (no time) - Format: locale-specific date - Date with time - Format: locale-specific datetime - Raw number display - Rounded integer (Math.round) - EUR currency format (€1,234.56) - Percentage format (12.34%) - Clickable mailto link ()
- phone - Clickable tel link ()
- link - External link that opens in new tab (target="_blank")$3
- array - Comma-separated array values
- json - Formatted JSON display with indentation
- countryFlag - Country flag image (requires ISO2 country code)
- persons - List of persons with "et al." for 3+ people$3
`jsx
const columns = [
{ accessorKey: 'name', header: 'Name', type: 'textTitle' },
{ accessorKey: 'description', header: 'Description', type: 'textDescription' },
{ accessorKey: 'email', header: 'Email', type: 'email' },
{ accessorKey: 'phone', header: 'Phone', type: 'phone' },
{ accessorKey: 'website', header: 'Website', type: 'link' },
{ accessorKey: 'salary', header: 'Salary', type: 'currency' },
{ accessorKey: 'completion', header: 'Progress', type: 'percentage' },
{ accessorKey: 'createdAt', header: 'Created', type: 'date', isDateColumn: true },
{ accessorKey: 'lastUpdated', header: 'Last Updated', type: 'datetime', isDateColumn: true },
{ accessorKey: 'country', header: 'Country', type: 'countryFlag' },
{ accessorKey: 'tags', header: 'Tags', type: 'array' },
{ accessorKey: 'metadata', header: 'Metadata', type: 'json' },
{ accessorKey: 'authors', header: 'Authors', type: 'persons' },
];
`$3
You have multiple options for cell rendering, each serving different use cases:
#### Option 1: Using Type Alone (Simplest)
Best for: Standard formatting without custom logic
`jsx
const columns = [
{
accessorKey: 'price',
header: 'Price',
type: 'currency' // Automatically formatted as €1,234.56
}
];
// No custom Cell needed - formatter is applied automatically
`#### Option 2: Type + cellClass
Best for: Adding CSS styling to formatted content
`jsx
const columns = [
{
accessorKey: 'status',
header: 'Status',
type: 'text',
cellClass: 'status-badge' // Formatted text wrapped in
}
];
`#### Option 3: Type + Custom Cell (Advanced)
Best for: Custom logic or styling while preserving type formatting
`jsx
// Custom cell that uses the type formatter and adds custom styling
const CustomStatusCell = ({ typeValue, cell, row }) => {
const rawValue = cell.getValue();
const formattedValue = typeValue; // Pre-formatted by type formatter
return (
color: rawValue === 'active' ? 'green' : 'red',
fontWeight: 'bold',
padding: '4px 8px',
borderRadius: '4px',
backgroundColor: rawValue === 'active' ? '#e8f5e9' : '#ffebee'
}}>
{formattedValue || rawValue} {/ Use formatted value or fallback /}
);
};const columns = [
{
accessorKey: 'status',
header: 'Status',
type: 'text', // Formatter is applied first
Cell: CustomStatusCell, // Custom component receives typeValue prop
}
];
`#### Option 4: Custom Cell Only (No Type)
Best for: Complete custom rendering without any formatter
`jsx
const CustomCell = ({ cell, row }) => {
const value = cell.getValue();
return (
{value}
{row.original.count}
);
};const columns = [
{
accessorKey: 'name',
header: 'Name',
Cell: CustomCell // No type - full control over rendering
}
];
`#### Custom Cell Props Reference
When using a custom
Cell component, you receive these props:`typescript
{
cell: Object, // MRT cell instance
row: Object, // MRT row instance
table: Object, // MRT table instance
typeValue: any, // Formatted value from type formatter (if type is defined)
// Standard MRT props...
}
`Important: Access
row.original to get the original data object.---
How Cell Rendering Works:
1. accessorFn/accessorKey evaluated: Value is extracted from row data
2. Type formatter applied: If
type is specified, DEFAULT_CELL_TYPES[type] processes the value
3. Content assigned: Formatted value becomes the base content
4. Custom Cell receives props: If Cell is defined, it receives:
- typeValue: The pre-formatted value
- All standard MRT cell props
5. CSS wrapper: If cellClass is defined, final content is wrapped in Rendering Priority:
`
Raw Data → accessorFn → Type Formatter → typeValue → Custom Cell → cellClass Wrapper → Final Output
`When to use each approach:
- Use type only for standard formatting (95% of cases)
- Use type + cellClass for simple styling needs
- Use type + Cell when you need formatting AND custom logic
- Use Cell only for completely custom rendering
---
Examples
$3
`jsx
import React, { useState } from 'react';
import DataGrid from '@insticc/react-datagrid-2';function UserGrid() {
const [selected, setSelected] = useState([]);
const columns = [
{ accessorKey: 'id', header: 'ID', type: 'integer' },
{ accessorKey: 'name', header: 'Name', type: 'textTitle' },
{ accessorKey: 'email', header: 'Email', type: 'email' },
{ accessorKey: 'role', header: 'Role', type: 'text' },
{ accessorKey: 'createdAt', header: 'Joined', type: 'date', isDateColumn: true },
];
const users = [
{ id: 1, name: 'John Doe', email: 'john@company.com', role: 'Admin', createdAt: '2024-01-15' },
{ id: 2, name: 'Jane Smith', email: 'jane@company.com', role: 'User', createdAt: '2024-02-20' },
{ id: 3, name: 'Bob Johnson', email: 'bob@company.com', role: 'Manager', createdAt: '2024-03-10' },
];
return (
columns={columns}
createRows={users}
rowKey="id"
selectData={setSelected}
pageSize={50}
itemsPerPage={[25, 50, 100]}
gridHeight={500}
/>
);
}
`$3
`jsx
function ConferenceGrid() {
const [selected, setSelected] = useState([]); const columns = [
{
accessorKey: 'acronym',
accessorFn: (row) => row.acronym ?? '', // Handle null/undefined
header: 'Acronym',
type: 'textTitle'
},
{
accessorKey: 'fullName',
accessorFn: (row) =>
${row.shortName || ''} - ${row.year || ''}, // Combine fields
header: 'Conference Name',
type: 'text'
},
{
accessorKey: 'papers',
accessorFn: (row) => row.numberPapers?.value ?? 0, // Nested object with fallback
header: 'Papers',
type: 'integer'
},
{
accessorKey: 'averageRating',
accessorFn: (row) => row.ratings?.average ?? 0, // Nested with default
header: 'Avg Rating',
type: 'number'
},
{
accessorKey: 'status',
accessorFn: (row) => row.isActive ? 'Active' : 'Inactive', // Conditional
header: 'Status',
type: 'text'
},
{
accessorKey: 'organizers',
accessorFn: (row) => row.organizers?.map(o => o.name).join(', ') ?? 'N/A', // Array processing
header: 'Organizers',
type: 'text'
}
]; const conferences = [
{
id: 1,
acronym: 'ICEIS',
shortName: 'International Conference on Enterprise Information Systems',
year: 2025,
numberPapers: { value: 150, trend: 'up' },
ratings: { average: 4.5, count: 200 },
isActive: true,
organizers: [{ name: 'John Doe' }, { name: 'Jane Smith' }]
},
{
id: 2,
acronym: null, // Will be handled by accessorFn
shortName: 'Conference on AI',
year: 2024,
numberPapers: null, // Will default to 0
ratings: { average: 3.8, count: 50 },
isActive: false,
organizers: []
}
];
return (
columns={columns}
createRows={conferences}
rowKey="id"
selectData={setSelected}
gridHeight={600}
/>
);
}
`$3
`jsx
function ProductGrid() {
const [selectedProducts, setSelectedProducts] = useState([]);
const [products, setProducts] = useState(initialProducts); const handleDelete = (rows) => {
const ids = rows.map(r => r.productId);
if (window.confirm(
Delete ${ids.length} product(s)?)) {
setProducts(prev => prev.filter(p => !ids.includes(p.productId)));
}
}; const handleEdit = (rows) => {
if (rows.length === 1) {
openEditModal(rows[0]);
}
};
const handleAddNew = () => {
openCreateModal();
};
const actions = [
{
name: 'Delete',
function: handleDelete,
tooltip: 'Delete selected products',
color: 'red',
icon: 'trash',
selectionMode: 'multi',
hasConfirmMessage: true,
confirmMessage: 'Are you sure you want to delete the selected products?'
},
{
name: 'Edit',
function: handleEdit,
tooltip: 'Edit product',
color: 'blue',
icon: 'edit',
selectionMode: 'single'
},
{
name: 'Add Product',
function: handleAddNew,
tooltip: 'Add new product',
color: 'green',
icon: 'plus',
selectionMode: 'always'
}
];
const columns = [
{ accessorKey: 'productId', header: 'ID', type: 'integer' },
{ accessorKey: 'name', header: 'Product Name', type: 'textTitle' },
{
accessorKey: 'price',
accessorFn: (row) => row.price ?? 0, // Ensure numeric value
header: 'Price',
type: 'currency'
},
{ accessorKey: 'stock', header: 'Stock', type: 'integer' },
{ accessorKey: 'category', header: 'Category', type: 'text' },
];
return (
columns={columns}
createRows={products}
rowKey="productId"
selectData={setSelectedProducts}
actions={actions}
hasExcelExport={true}
hasPdfExport={true}
gridHeight={600}
/>
);
}
`$3
`jsx
function TaskGrid() {
const [tasks, setTasks] = useState(initialTasks);
const [selected, setSelected] = useState([]);
const [hideCompleted, setHideCompleted] = useState(false);
const [hideArchived, setHideArchived] = useState(true); // Filter data based on filter states
const filteredTasks = useMemo(() => {
return tasks.filter(task => {
if (hideCompleted && task.status === 'completed') return false;
if (hideArchived && task.isArchived) return false;
return true;
});
}, [tasks, hideCompleted, hideArchived]);
const filterActions = [
{
name: 'Completed',
state: hideCompleted,
function: () => setHideCompleted(!hideCompleted),
tooltip: hideCompleted ? 'Show completed tasks' : 'Hide completed tasks',
key: 'filter-completed'
},
{
name: 'Archived',
state: hideArchived,
function: () => setHideArchived(!hideArchived),
tooltip: hideArchived ? 'Show archived tasks' : 'Hide archived tasks',
key: 'filter-archived'
},
{
// Example with dynamic name and conditional visibility
state: hideUrgent,
name: hideUrgent ? "Hiding Urgent" : "Showing Urgent",
tooltip: hideUrgent ? "Show urgent tasks" : "Hide urgent tasks",
function: () => setHideUrgent(!hideUrgent),
visible: !!setHideUrgent, // Only show if handler exists
}
];
const columns = [
{ accessorKey: 'id', header: 'ID', type: 'integer' },
{ accessorKey: 'title', header: 'Task', type: 'textTitle' },
{ accessorKey: 'status', header: 'Status', type: 'text' },
{ accessorKey: 'dueDate', header: 'Due Date', type: 'date', isDateColumn: true },
];
return (
columns={columns}
createRows={filteredTasks}
rowKey="id"
selectData={setSelected}
filterActions={filterActions}
gridHeight={600}
/>
);
}
`$3
`jsx
function ProjectGrid() {
const [selectedItems, setSelectedItems] = useState([]); const columns = [
{ accessorKey: 'name', header: 'Name', type: 'textTitle' },
{ accessorKey: 'status', header: 'Status', type: 'text' },
{ accessorKey: 'assignee', header: 'Assignee', type: 'text' },
{ accessorKey: 'dueDate', header: 'Due Date', type: 'date', isDateColumn: true },
];
const data = [
{
id: 1,
name: 'Project Alpha',
status: 'Active',
assignee: 'John Doe',
dueDate: '2025-06-30',
subRows: [
{ id: '1.1', name: 'Task 1: Design', status: 'Complete', assignee: 'Jane', dueDate: '2025-02-15' },
{ id: '1.2', name: 'Task 2: Development', status: 'In Progress', assignee: 'Bob', dueDate: '2025-04-30' },
{ id: '1.3', name: 'Task 3: Testing', status: 'Not Started', assignee: 'Alice', dueDate: '2025-06-15' }
]
},
{
id: 2,
name: 'Project Beta',
status: 'Planning',
assignee: 'Jane Smith',
dueDate: '2025-12-31',
subRows: [
{ id: '2.1', name: 'Task 1: Requirements', status: 'In Progress', assignee: 'John', dueDate: '2025-03-01' }
]
}
];
return (
columns={columns}
createRows={data}
rowKey="id"
selectData={setSelectedItems}
hasSubRows={true}
enableExpanding={true}
gridHeight={500}
/>
);
}
`$3
`jsx
function LargeDataGrid() {
const [selectedRows, setSelectedRows] = useState([]); // Custom cell with type support
const StatusCell = ({ typeValue, cell, row }) => {
const value = cell.getValue();
const getColor = (status) => {
switch (status) {
case 'active': return 'green';
case 'pending': return 'orange';
case 'error': return 'red';
default: return 'grey';
}
};
return (
color: getColor(value),
fontWeight: 'bold',
padding: '2px 8px',
borderRadius: '4px',
backgroundColor:
${getColor(value)}22
}}>
{typeValue || value}
);
}; const PriorityCell = ({ cell, row }) => {
const priority = cell.getValue();
const icons = {
high: '🔴',
medium: '🟡',
low: '🟢'
};
return (
{icons[priority]} {priority.toUpperCase()}
);
};
const getRowStyle = ({ row }) => {
const styles = {};
if (row.original.status === 'error') {
styles.backgroundColor = '#ffebee';
}
if (row.original.priority === 'high') {
styles.borderLeft = '3px solid red';
}
if (row.original.isArchived) {
styles.opacity = 0.5;
}
return styles;
};
const columns = [
{ accessorKey: 'id', header: 'ID', type: 'integer' },
{
accessorKey: 'status',
header: 'Status',
type: 'text',
Cell: StatusCell
},
{
accessorKey: 'priority',
header: 'Priority',
Cell: PriorityCell
},
{ accessorKey: 'name', header: 'Name', type: 'text' },
{
accessorKey: 'value',
accessorFn: (row) => row.value ?? 0, // Ensure numeric value for currency
header: 'Value',
type: 'currency'
},
{
accessorKey: 'progress',
accessorFn: (row) => row.progress ?? 0, // Ensure numeric value for percentage
header: 'Progress',
type: 'percentage'
},
{ accessorKey: 'updatedAt', header: 'Updated', type: 'datetime', isDateColumn: true },
];
// Generate large dataset
const largeDataset = Array.from({ length: 5000 }, (_, i) => ({
id: i + 1,
status: ['active', 'pending', 'error'][i % 3],
priority: ['high', 'medium', 'low'][i % 3],
name:
Item ${i + 1},
value: Math.random() * 10000,
progress: Math.random(),
updatedAt: new Date(Date.now() - Math.random() 365 24 60 60 * 1000).toISOString(),
isArchived: i % 10 === 0
})); return (
columns={columns}
createRows={largeDataset}
rowKey="id"
selectData={setSelectedRows}
enableVirtualization={true}
enableCompactStyleMode={true}
rowHeight={40}
fontSize={12}
gridHeight="calc(100vh - 200px)"
getRowStyle={getRowStyle}
pageSize={100}
itemsPerPage={[50, 100, 200, 500]}
/>
);
}
`$3
`jsx
function AdvancedGrid() {
const [data, setData] = useState([]);
const [cacheLoading, setCacheLoading] = useState(false);
const [selectedRows, setSelectedRows] = useState([]);
const [visibleRowCount, setVisibleRowCount] = useState(0); const refreshData = async () => {
setCacheLoading(true);
try {
const newData = await fetchLatestData();
setData(newData);
} catch (error) {
console.error('Failed to refresh data:', error);
} finally {
setCacheLoading(false);
}
};
const handleVisibleRowsChange = (rows) => {
setVisibleRowCount(rows.length);
console.log('Visible rows:', rows);
};
const exportCustom = () => {
console.log('Custom export logic');
};
const actions = [
{
name: 'Process',
function: (rows) => processSelectedRows(rows),
tooltip: 'Process selected items',
color: 'blue',
icon: 'cog',
selectionMode: 'multi'
}
];
const extraActions = [
{
function: exportCustom,
content: 'Custom Export',
tooltip: 'Export with custom format',
icon: 'file alternate outline'
}
];
const columns = [
{ accessorKey: 'id', header: 'ID', type: 'integer' },
{ accessorKey: 'name', header: 'Name', type: 'textTitle' },
{ accessorKey: 'status', header: 'Status', type: 'text' },
{
accessorKey: 'amount',
accessorFn: (row) => row.amount ?? 0, // Ensure numeric value
header: 'Amount',
type: 'currency'
},
{ accessorKey: 'createdAt', header: 'Created', type: 'datetime', isDateColumn: true },
];
return (
columns={columns}
createRows={data}
rowKey="id"
selectData={setSelectedRows}
// Actions
actions={actions}
extraActions={extraActions}
// Advanced features
enableGlobalFilter={true}
globalFilterFn="fuzzy"
enableColumnFilterModes={true}
enableFixedHeader={true}
enableFixedActions={true}
// Cache management
updateCache={refreshData}
cacheUpdateText="Refresh data from server"
cacheUpdating={cacheLoading}
// Callbacks
onVisibleRowsChange={handleVisibleRowsChange}
// Exports
hasExcelExport={true}
hasPdfExport={true}
// Help
gridHelper={{
title: 'Data Grid Help',
content: (
Quick Guide
- Selection: Click rows to select, use checkboxes for multi-select
- Filtering: Use column filters to search specific fields
- Global Search: Search across all columns at once
- Sorting: Click column headers to sort
- Export: Use Excel or PDF buttons to export data
- Refresh: Click cache button to reload latest data
Currently showing: {visibleRowCount} rows
)
}}
// Display
gridHeight={700}
pageSize={100}
itemsPerPage={[50, 100, 200]}
/>
);
}
`$3
`jsx
function OrderGrid() {
const [orders, setOrders] = useState([]);
const [selected, setSelected] = useState([]); // Disable completed and cancelled orders from selection
const getDisabledRows = () => {
return orders
.filter(order => ['completed', 'cancelled'].includes(order.status))
.map(order => order.orderId);
};
const getRowStyle = ({ row }) => {
const status = row.original.status;
switch (status) {
case 'pending':
return { backgroundColor: '#fff3cd' };
case 'processing':
return { backgroundColor: '#cfe2ff' };
case 'completed':
return { backgroundColor: '#d1e7dd', opacity: 0.7 };
case 'cancelled':
return { backgroundColor: '#f8d7da', opacity: 0.7 };
default:
return {};
}
};
const columns = [
{ accessorKey: 'orderId', header: 'Order ID', type: 'text' },
{ accessorKey: 'customer', header: 'Customer', type: 'textTitle' },
{
accessorKey: 'total',
accessorFn: (row) => row.total ?? 0, // Ensure numeric value
header: 'Total',
type: 'currency'
},
{ accessorKey: 'status', header: 'Status', type: 'text' },
{ accessorKey: 'orderDate', header: 'Order Date', type: 'datetime', isDateColumn: true },
];
return (
columns={columns}
createRows={orders}
rowKey="orderId"
selectData={setSelected}
disableRows={getDisabledRows()}
getRowStyle={getRowStyle}
gridHeight={600}
/>
);
}
`---
API Reference
$3
`typescript
interface ColumnDefinition {
// Required
accessorKey: string; // Key identifier for the column
header: string; // Column header text
// Data Access (choose one)
// Option 1: Direct property access (default when no accessorFn)
// Option 2: Custom accessor function
accessorFn?: (row: Object) => any; // Function to extract/compute value from row
// Type & Rendering
type?: string; // Cell type for automatic formatting
Cell?: React.Component; // Custom cell renderer (receives typeValue)
cellClass?: string; // CSS class wrapper for cell content
// Filtering
enableColumnFilter?: boolean; // Default: true
enableColumnFilterModes?: boolean;// Default: true
filterFn?: string | function; // Default: 'contains' (or undefined for dates)
// Sorting
enableSorting?: boolean; // Default: true
sortingFn?: string | function; // Default: 'basic' (or custom for dates)
isDateColumn?: boolean; // Special date handling (default: false)
// Display
enableResizing?: boolean; // Default: true
grow?: boolean; // Column can grow (default: true)
enableClickToCopy?: boolean; // Default: false
enableColumnActions?: boolean; // Default: false
// Additional
locale?: string; // Locale for formatting (e.g., 'en-US')
onlyFlag?: boolean; // For countryFlag type
columnDef?: object; // Additional metadata
}
`$3
`typescript
interface ActionObject {
// Required
name: string; // Button label
function: (selectedRows: Array, table?: Object) => void; // Click handler
// Display
tooltip?: string; // Hover tooltip
color?: 'blue' | 'red' | 'green' | 'yellow' | 'orange' | 'black' | 'grey' |
'teal' | 'brown' | 'violet' | 'purple' | 'olive' | 'pink';
icon?: string | React.Element; // Icon name or element
// Behavior
selectionMode?: 'single' | 'multi' | 'always';
confirmMessage?: string | React.Element;
hasConfirmMessage?: boolean;
disabled?: boolean;
visible?: boolean; // Default: true
// Toggle mode
toggle?: boolean;
active?: boolean;
// Other
key?: string; // Unique React key
}
`$3
`typescript
interface FilterActionObject {
// Required
name: string; // Button label
function: () => void; // Toggle handler
state: boolean; // Current filter state (true=hidden, false=shown)
// Display
tooltip?: string; // Hover tooltip
icon?: string | React.Element; // Icon name or element (default: eye/eye-slash based on state)
visible?: boolean; // Show/hide the button (default: true)
// Behavior
disabled?: boolean; // Manually disable the button
key?: string; // Unique React key (defaults to name)
}
`$3
`typescript
interface ExtraActionObject {
// Required
function: () => void; // Click handler
content: string | React.Element; // Button content/label
// Display
tooltip?: string; // Hover tooltip
icon?: string | React.Element; // Icon name or element
style?: React.CSSProperties; // Custom button styles
propsButton?: object; // Additional Semantic UI Button props
visible?: boolean; // Show/hide the button (default: true)
}
`$3
`typescript
interface DataRow {
[rowKey: string]: any; // Unique identifier (required)
[key: string]: any; // Other data fields
// Optional: For hierarchical data
subRows?: Array;
isSubRow?: boolean;
}
`---
Performance Tips
$3
`jsx
// For 1000+ rows
enableVirtualization={true}
`$3
`jsx
// Smaller rows = more visible data
rowHeight={40}
enableCompactStyleMode={true}
fontSize={12}
`$3
`jsx
// Reduce overhead by disabling features you don't need
enableDensityToggle={false}
enableFullScreenToggle={false}
enableGlobalFilter={false}
enableColumnFilterModes={false}
`$3
`jsx
// Don't render too many rows initially
pageSize={50} // Instead of 150
itemsPerPage={[25, 50, 100]}
`$3
`jsx
// Only include necessary IDs
selectedIds={criticalIds} // Instead of selecting all rows
`$3
`jsx
// Use typeValue when available
const MyCell = ({ typeValue, cell }) => {
return typeValue || cell.getValue(); // Prefer pre-formatted typeValue
};// Memoize expensive computations
const ExpensiveCell = React.memo(({ cell }) => {
const processedValue = useMemo(() => expensiveComputation(cell.getValue()), [cell]);
return
{processedValue};
});
`$3
`jsx
// Bad - Complex computation on every render/filter/sort
accessorFn: (row) => {
return expensiveCalculation(row.data);
}// Good - Simple, fast operations
accessorFn: (row) => row.data?.value ?? 0
// Better - Pre-process data before passing to grid
const processedData = rawData.map(row => ({
...row,
computedValue: expensiveCalculation(row.data)
}));
`$3
`jsx
// Hide columns that aren't immediately needed
columnVisibilityState={{
metadata: false,
internalId: false,
debugInfo: false
}}
`$3
`jsx
// Keep getRowStyle lightweight
getRowStyle={({ row }) => {
// Simple conditional - avoid heavy computation
return row.original.isHighlighted ? { backgroundColor: '#fffacd' } : {};
}}
`$3
`jsx
// Instead of multiple state updates, batch them
const handleMultipleChanges = () => {
// Use a single state update with derived values
setData(prevData => processAndUpdate(prevData));
};
`$3
`jsx
// Use keys properly for subRows
const data = subRowData.map((item, index) => ({
...item,
id: ${parentId}.${index} // Stable, unique keys
}));
`---
Browser Support
- Chrome: Latest version (recommended)
- Firefox: Latest version
- Safari: Latest version
- Edge: Latest version (Chromium-based)
$3
- CSS Grid support (all modern browsers)
- CSS Sticky positioning for fixed headers
- Flexbox for layouts---
Troubleshooting
$3
#### Issue: Rows not selecting when clicked
Symptoms: Clicking rows doesn't select them, checkboxes don't appear
Solutions:
- Verify
disableSelect={false} (this is the default)
- Ensure selectData callback is provided
- Check that rowKey matches your data's unique identifier property
- Verify rows aren't in the disableRows array`jsx
// Correct configuration
rowKey="id" // Matches data[0].id
selectData={handleSelection} // Required callback
disableSelect={false} // Optional - default is false
disableRows={[]} // No disabled rows
/>
`#### Issue: Date columns not sorting correctly
Symptoms: Dates sort alphabetically instead of chronologically
Solutions:
- Set
isDateColumn={true} on date columns
- Ensure date values are in valid ISO 8601 format (YYYY-MM-DD or YYYY-MM-DDTHH:mm:ss)
- Check that date strings are parseable by JavaScript Date constructor`jsx
// Correct date column configuration
{
accessorKey: 'createdAt',
header: 'Created Date',
type: 'date',
isDateColumn: true // Enables date-aware sorting
}// Data format
const data = [
{ id: 1, createdAt: '2025-01-15' }, // ISO 8601 format
{ id: 2, createdAt: '2024-12-20' },
];
`#### Issue: Fixed headers not working
Symptoms: Headers scroll with content instead of staying fixed
Solutions:
- Set
enableFixedHeader={true} (default is true)
- Ensure gridHeight is set to a specific numeric value or CSS string
- Do not use gridHeight="fit-content" with fixed headers
- Check for CSS conflicts with grid-sticky-header class`jsx
// Correct fixed header configuration
enableFixedHeader={true}
gridHeight={600} // Or "80vh", not "fit-content"
/>
`#### Issue: Fixed actions toolbar not sticking
Symptoms: Action buttons scroll instead of staying at top
Solutions:
- Enable both
enableFixedHeader={true} and enableFixedActions={true}
- Verify gridHeight is set to a specific value
- Check for CSS conflicts with grid-sticky-actions class`jsx
enableFixedHeader={true}
enableFixedActions={true}
gridHeight={700}
/>
`#### Issue: Selection state not syncing with parent component
Symptoms: External state doesn't match grid selection
Solutions:
- Use the
selectedIds prop to control selection from parent
- Component automatically syncs when selectedIds prop changes
- Ensure rowKey values in selectedIds match data`jsx
const [externalSelection, setExternalSelection] = useState([1, 5, 10]); selectedIds={externalSelection} // Controlled selection
selectData={(rows) => {
const ids = rows.map(r => r.id);
setExternalSelection(ids);
}}
/>
`#### Issue: Export buttons not appearing
Symptoms: Excel/PDF export buttons are not visible
Solutions:
- Set
hasExcelExport={true} and/or hasPdfExport={true}
- Check that disableSideActions={false} (default)
- Ensure toolbar has space (not too many actions)
- Verify enableTopToolbar={true} (default)`jsx
hasExcelExport={true}
hasPdfExport={true}
enableTopToolbar={true}
disableSideActions={false}
/>
`#### Issue: Type formatter not working
Symptoms: Column values appear as raw data instead of formatted
Solutions:
- Verify column has
type property defined
- Check that type value exists in DEFAULT_CELL_TYPES (e.g., 'text', 'date', 'currency', 'email')
- Ensure data values are in correct format for the type
- Check browser console for errors`jsx
// Correct type configuration
{
accessorKey: 'price',
header: 'Price',
type: 'currency' // Must match a valid type
}
`#### Issue: Custom Cell component not receiving typeValue
Symptoms:
typeValue prop is undefined in custom CellSolutions:
- Verify column has both
type AND Cell defined
- Check that type matches a key in DEFAULT_CELL_TYPES
- typeValue only exists when type formatter is applied`jsx
// Correct configuration for typeValue
const CustomCell = ({ typeValue, cell }) => {
console.log(typeValue); // Will be defined
return {typeValue};
};{
accessorKey: 'amount',
type: 'currency', // Required for typeValue
Cell: CustomCell // Will receive typeValue
}
`#### Issue: accessorFn not being used for filtering/sorting
Symptoms: Filters and sorts use raw data instead of accessorFn result
Solutions:
- Verify
accessorFn is defined correctly
- The returned value from accessorFn is what gets filtered/sorted
- For complex objects, ensure accessorFn returns a simple value`jsx
// Bad - Returns object (hard to filter/sort)
accessorFn: (row) => ({ value: row.data })// Good - Returns simple value
accessorFn: (row) => row.data?.value ?? 0
`#### Issue: Virtualization causing scroll issues
Symptoms: Jerky scrolling, rows not rendering, blank spaces
Solutions:
- Ensure
rowHeight is set accurately
- Don't use dynamic row heights with virtualization
- Check that enableVirtualization={true} is actually needed (only for 1000+ rows)
- Verify data doesn't change reference on every render`jsx
// Good for virtualization
enableVirtualization={true}
rowHeight={40} // Fixed height
createRows={stableDataReference} // Don't recreate array
/>
`#### Issue: Actions not enabling/disabling correctly
Symptoms: Action buttons stay disabled when rows are selected
Solutions:
- Check
selectionMode setting ('single', 'multi', 'always')
- Verify disabled prop isn't set to true
- Ensure rows are actually being selected (check selectData callback)`jsx
actions={[
{
name: 'Edit',
selectionMode: 'single', // Requires exactly 1 row
function: handleEdit,
disabled: false // Not manually disabled
}
]}
`#### Issue: Hierarchical data (subRows) not working
Symptoms: SubRows don't expand or aren't selectable
Solutions:
- Set
hasSubRows={true}
- Set enableExpanding={true} to show expand icons
- Ensure data has correct subRows structure
- SubRow IDs should follow pattern: "parentId.index"
`jsx
const hierarchicalData = [
{
id: 1,
name: 'Parent',
subRows: [
{ id: '1.1', name: 'Child 1' },
{ id: '1.2', name: 'Child 2' }
]
}
]; hasSubRows={true}
enableExpanding={true}
createRows={hierarchicalData}
/>
`#### Issue: Cache update button not appearing
Symptoms: Cache/refresh button is not visible
Solutions:
- Provide
updateCache function prop
- Optionally set cacheUpdateText for tooltip
- Button only appears when updateCache is defined`jsx
updateCache={() => fetchLatestData()}
cacheUpdateText="Refresh from server"
cacheUpdating={isLoading}
/>
`#### Issue: Row styles not applying
Symptoms:
getRowStyle returns styles but they don't appearSolutions:
- Check that returned object contains valid CSS properties
- Verify function is actually being called
- CSS specificity might be overriding - use
!important if needed
- Check browser console for CSS errors`jsx
getRowStyle={({ row }) => {
console.log('Styling row:', row.id); // Debug
return {
backgroundColor: row.original.isHighlighted ? '#fffacd !important' : 'white'
};
}}
`#### Issue: Filters not working
Symptoms: Column filters don't filter data
Solutions:
- Verify
enableColumnFilter={true} on columns (default)
- Check that filterFn is valid
- Ensure data values match filter input type
- If using accessorFn, ensure it returns filterable values`jsx
{
accessorKey: 'status',
header: 'Status',
enableColumnFilter: true,
filterFn: 'contains' // or 'equals', 'startsWith', etc.
}// With accessorFn
{
accessorKey: 'papers',
accessorFn: (row) => row.numberPapers?.value ?? 0, // Returns number for filtering
header: 'Papers',
type: 'integer'
}
`---
Important Notes
$3
- Disabled Select: When disableSelect={true} hide the selection checkbox/radio and cannot be selected
- Single selection mode: When enableMultiRowSelection={false}, clicking a row deselects all others
- Multi-selection: Use checkboxes when enableMultiRowSelection={true}
- Selection state: Controlled via rowSelection state and selectData callback$3
- enableFixedHeader uses CSS position: sticky on column headers
- enableFixedActions (requires enableFixedHeader={true}) also pins the toolbar
- Both require gridHeight to be set to a specific value (not 'fit-content')
- CSS classes: grid-sticky-header and grid-sticky-actions$3
- Use type: 'date' for date-only display (no time)
- Use type: 'datetime' for full datetime display
- Default locale is 'pt-PT' - override with locale prop on column
- Date values should be ISO 8601 format for best results$3
- accessorFn is called for every cell render, filter operation, and sort operation
- Keep computations lightweight
- Avoid creating new objects/arrays in accessorFn
- Pre-process complex data before passing to the grid when possible
- The returned value is what gets filtered and sorted$3
- Component is wrapped with MUI's LocalizationProvider using AdapterDateFns
- Required for date picker functionality in filters
- No need to add this provider in your own code$3
- SubRow IDs follow pattern: "parentId.subRowIndex" (e.g., "1.0", "1.1")
- Selection works on both parent and child rows
- Visual depth indicated by background color and padding
- Requires hasSubRows={true} to enable$3
- Virtualization is recommended for 1000+ rows
- Compact style mode reduces render overhead
- Custom cell components should be memoized when possible
- Avoid recreating data arrays on every render
- Keep accessorFn computations lightweight$3
- Component does NOT use localStorage or sessionStorage
- All state is maintained in React state (useState)
- Selection state is ephemeral unless managed by parent---
Dependencies
This component requires the following peer dependencies:
$3
- react (^16.8.0 || ^17.0.0 || ^18.0.0) - React framework
- prop-types - Runtime type checking for React props
- material-react-table - Core table functionality and hooks
- @mui/material - Material UI components
- @mui/x-date-pickers - Date picker components for filters
- date-fns - Date manipulation and formatting
- semantic-ui-react - Semantic UI React components for buttons and icons
- bootstrap - Base CSS framework
- semantic-ui-css - Semantic UI CSS styles$3
`json
{
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0 || ^18.0.0",
"material-react-table": "^2.0.0",
"@mui/material": "^5.0.0",
"semantic-ui-react": "^2.0.0"
}
}
``---
ISC
---