@insticc/react-datagrid-2
v1.1.31
Published
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.
Readme
DataGrid Component
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.
Table of Contents
- Installation
- Basic Usage
- Props Reference
- Column Types
- Examples
- API Reference
- Performance Tips
- Browser Support
- Troubleshooting
Installation
npm install @insticc/react-datagrid-2Required Dependencies
npm install react prop-types material-react-table semantic-ui-react @mui/material @mui/x-date-pickers date-fns bootstrap semantic-ui-cssBasic Usage
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: '[email protected]', createdAt: '2025-01-15' },
{ id: '2', name: 'Jane Smith', email: '[email protected]', createdAt: '2025-02-20' },
];
return (
<DataGrid
columns={columns}
createRows={data}
rowKey="id"
selectData={setSelectedRows}
hasExcelExport={true}
hasPdfExport={true}
/>
);
}Props Reference
Core Props
columns (required)
- Type:
Array<ColumnDefinition> - Description: Array of column definitions that determine how data is displayed
- Example:
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:
typeonly: Formatter applied automaticallytype+cellClass: Formatted content wrapped in div with CSS classtype+Cell: Custom component receivestypeValue(formatted content) as propCellonly: Full custom rendering without type formatter
createRows (required)
- Type:
Array<Object> - Description: Array of data objects to display in the grid
- Example:
const data = [
{ id: 1, name: 'John', email: '[email protected]' },
{ id: 2, name: 'Jane', email: '[email protected]' }
];rowKey (required)
- Type:
string - Description: Property name used as unique identifier for each row
- Example:
rowKey="id"orrowKey="uuid"
selectData (required)
- Type:
function - Description: Callback function that receives selected rows whenever selection changes
- Signature:
(selectedRows: Array<Object>) => void - Example:
const handleSelection = (rows) => {
console.log('Selected rows:', rows);
console.log('Selected IDs:', rows.map(r => r.id));
};
<DataGrid selectData={handleSelection} />Column Configuration
Understanding accessorKey vs accessorFn
The DataGrid provides two ways to access data from your rows:
accessorKey (Simple Access)
- Type:
string - Use when: You want to access a property directly from the row object
- Example:
{
accessorKey: 'name', // Accesses row.name
header: 'Name'
}accessorFn (Custom Access)
- Type:
(row: Object) => any - 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
accessorKeyif both are defined - Examples:
// 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:
accessorFnis executed for every cell render, filter, and sort operation- Keep the function lightweight to avoid performance issues
- The returned value is what gets filtered and sorted (not the original cell display)
- When using
accessorFn, you typically still needaccessorKeyas a unique identifier for the column accessorFnvalue is passed to the type formatter (iftypeis specified)
Performance Tip:
// Bad - Creates new object every time
accessorFn: (row) => ({ value: row.data, label: row.name })
// Good - Returns simple value
accessorFn: (row) => row.data?.value ?? 0columnVisibilityState
- Type:
object - Default:
{} - Description: Controls which columns are visible/hidden
- Example:
columnVisibilityState={{
email: false, // Hide email column
phone: true, // Show phone column
id: false // Hide ID column
}}columnOrder
- Type:
Array<string> - Default:
[] - Description: Defines the order of columns by their accessorKey
- Example:
columnOrder={['name', 'email', 'createdAt', 'id']}Actions & Toolbar
actions
- Type:
Array<ActionObject> - Default:
null - Description: Array of custom action buttons displayed in the toolbar
- Action Object Properties:
name(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 selection
confirmMessage(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:
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'
}
]}filterActions
- Type:
Array<FilterActionObject> - Default:
null - Description: Array of toggle filter action buttons displayed in the toolbar for showing/hiding data based on filters
- Filter Action Object Properties:
name(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)
- Button Appearance:
- When
state=true: Orange color with eye-slash icon (items hidden) - When
state=false: Green color with eye icon (items shown)
- When
- Example:
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
}
]}extraActions
- Type:
Array<ExtraActionObject> - Default:
null - Description: Additional custom action buttons displayed on the right side of the toolbar
- Extra Action Object Properties:
function(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:
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 }
}
]}enableTopToolbar
- Type:
boolean - Default:
true - Description: Show/hide the top toolbar containing actions and pagination
enableBottomToolbar
- Type:
boolean - Default:
false - Description: Show/hide the bottom toolbar
hasClearFiltersBtn
- Type:
boolean - Default:
true - Description: Show/hide the "Clear Filters" button in toolbar
hasClearSelectionBtn
- Type:
boolean - Default:
true - Description: Show/hide the "Clear Selection" button in toolbar
- Note: Only visible when
disableSelect={false}ordisableRowsarray has items
disableAllActions
- Type:
boolean - Default:
false - Description: Hide all action buttons in the top toolbar
disableSideActions
- Type:
boolean - Default:
false - Description: Hide side action buttons (export, cache, clear filters, help) while keeping main actions visible
gridHelper
- Type:
object | null - Default:
null - Description: Adds a help button with custom content in a modal dialog
- Required Properties (if defined):
title(string|element, required): Help dialog titlecontent(string|element, required): Help dialog content
- Example:
gridHelper={{
title: 'Grid Instructions',
content: (
<div>
<h3>How to use this grid:</h3>
<ul>
<li>Use the filters above each column to search data</li>
<li>Click rows to select them</li>
<li>Use action buttons to perform operations</li>
<li>Export data using the Excel or PDF buttons</li>
</ul>
</div>
)
}}Export Options
hasExcelExport
- Type:
boolean - Default:
false - Description: Enable Excel export button in the toolbar
hasPdfExport
- Type:
boolean - Default:
false - Description: Enable PDF export button in the toolbar
Export Behavior:
- Both export buttons are rendered by the
ExportActionscomponent - 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
Selection & Interaction
disableSelect
- Type:
boolean - Default:
false - Description: Completely disable row selection checkboxes and click-to-select behavior
enableMultiRowSelection
- Type:
boolean - Default:
true - Description: Allow selecting multiple rows at once
- Behavior:
true- Users can select multiple rows using checkboxes or Shift+Clickfalse- Only one row can be selected at a time
selectAllMode
- Type:
string - Default:
'page' - Options:
'page','all' - Description:
'page'- "Select All" checkbox selects only rows on current page'all'- "Select All" checkbox selects all filtered rows across all pages
selectedIds
- Type:
Array - Default:
[] - Description: Array of row IDs that should be pre-selected when grid loads
- Example:
selectedIds={[1, 5, 10]} // Pre-select rows with these IDs- Note: Component syncs automatically when this prop changes
disableRows
- Type:
Array - Default:
[] - Description: Array of row IDs (based on
rowKey) that should be disabled and cannot be selected - Example:
disableRows={[3, 7, 9]} // Disable selection for these row IDs- Visual: Disabled rows are shown with gray background (
#e3e3e3)
hasSubRows
- Type:
boolean - Default:
false - Description: Enable support for hierarchical/nested rows
- Requirements: Data must include
subRowsproperty for parent rows - Example Data:
const data = [
{
id: 1,
name: 'Parent Row',
subRows: [
{ id: '1.1', name: 'Child Row 1' },
{ id: '1.2', name: 'Child Row 2' }
]
}
];enableExpanding
- Type:
boolean - Default:
false - Description: Show expand/collapse icons for rows with subRows
- Requires:
hasSubRows={true}
Pagination & Display
enablePagination
- Type:
boolean - Default:
true - Description: Enable/disable pagination controls
pagination
- Type:
string - Default:
'both' - Options:
'top','bottom','both' - Description: Position of pagination controls
- Note: When using
'top', pagination is integrated into the top toolbar
pageSize
- Type:
number - Default:
150 - Description: Number of rows displayed per page initially
itemsPerPage
- Type:
Array<number> - Default:
[50, 100, 150] - Description: Options available in the rows-per-page dropdown
- Example:
itemsPerPage={[10, 25, 50, 100, 200]}Styling & Layout
rowHeight
- Type:
number - Default:
75 - Description: Minimum height of each row in pixels
fontSize
- Type:
number - Default:
14 - Description: Base font size for grid content in pixels
- Compact Mode: When
enableCompactStyleMode={true}, responsive sizing is used:clamp(fontSize-3px, 1.1vw, fontSize)
gridHeight
- Type:
number | string - Default:
600 - Description: Maximum height of the grid container
- Examples:
gridHeight={600} // 600px fixed height
gridHeight="80vh" // 80% of viewport height
gridHeight="calc(100vh - 200px)" // Dynamic height calculationenableCompactStyleMode
- Type:
boolean - Default:
false - 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
getRowStyle
- Type:
function - Description: Custom function to apply conditional styles to rows based on data
- Signature:
({ row }) => object - Example:
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;
}}enableFixedHeader
- Type:
boolean - Default:
true - Description: Pin column headers to top when scrolling vertically
- Implementation: Uses CSS sticky positioning with class
grid-sticky-header
enableFixedActions
- Type:
boolean - Default:
false - Description: Pin action toolbar to top when scrolling
- Requires:
enableFixedHeader={true} - Implementation: Uses CSS sticky positioning with class
grid-sticky-actions
Advanced Features
enableGlobalFilter
- Type:
boolean - Default:
false - Description: Show global search input that filters across all columns
globalFilterFn
- Type:
string - Default:
'contains' - Options:
'contains','fuzzy','between','equals','greaterThan','lessThan','notEquals','lessThanOrEqualTo','greaterThanOrEqualTo','empty','notEmpty','startsWith','endsWith','betweenInclusive' - Description: Filter function used for global search
enableColumnFilterModes
- Type:
boolean - Default:
true - Description: Allow users to change filter type per column (contains, equals, regex, etc.)
- Available Modes: Rendered through
ColumnFiltercomponent
enableVirtualization
- Type:
boolean - Default:
false - Description: Enable row and column virtualization for large datasets
- Recommended: For grids with 1000+ rows
- Configuration:
- Row virtualizer:
overscan: 5 - Column virtualizer:
overscan: columns.length - Scroll-to-top on sort change
- Row virtualizer:
enableFullScreenToggle
- Type:
boolean - Default:
false - Description: Show fullscreen toggle button in toolbar
enableDensityToggle
- Type:
boolean - Default:
false - Description: Show density toggle button (compact/comfortable/spacious)
Cache & Updates
updateCache
- Type:
function - Default:
undefined - Description: Callback function triggered when cache update button is clicked
- Signature:
() => void - Example:
updateCache={() => {
fetchLatestData();
}}- Note: Cache button only appears when this prop is provided
cacheUpdateText
- Type:
string - Default:
undefined - Description: Tooltip text displayed on hover over the cache update button
- Example:
"Refresh data from server"
cacheUpdating
- Type:
boolean - Default:
false - Description: Shows loading state on cache update button
- Visual: Changes button icon to loading spinner
- Disables: Button is disabled while
true
Callbacks
onVisibleRowsChange
- Type:
function - Description: Called whenever the visible rows change (filtering, sorting, pagination)
- Signature:
(visibleRows: Array<Object>) => void - Example:
onVisibleRowsChange={(rows) => {
console.log('Currently visible:', rows.length);
updateDashboardStats(rows);
}}Column Types
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.
Text Types
text- Plain text displaytextTitle- Bold text (font-weight: bold)textDescription- Gray text (#666666)textSmall- Small font size text
Date Types
date- Date only (no time) - Format: locale-specific datedatetime- Date with time - Format: locale-specific datetime
Number Types
number- Raw number displayinteger- Rounded integer (Math.round)currency- EUR currency format (€1,234.56)percentage- Percentage format (12.34%)
Link Types
email- Clickable mailto link (<a href="mailto:...">)phone- Clickable tel link (<a href="tel:...">)link- External link that opens in new tab (target="_blank")
Complex Types
array- Comma-separated array valuesjson- Formatted JSON display with indentationcountryFlag- Country flag image (requires ISO2 country code)persons- List of persons with "et al." for 3+ people
Example with Types
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' },
];Custom Cell Renderers with Type Support
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
const columns = [
{
accessorKey: 'price',
header: 'Price',
type: 'currency' // Automatically formatted as €1,234.56
}
];
// No custom Cell needed - formatter is applied automaticallyOption 2: Type + cellClass
Best for: Adding CSS styling to formatted content
const columns = [
{
accessorKey: 'status',
header: 'Status',
type: 'text',
cellClass: 'status-badge' // Formatted text wrapped in <div class="status-badge">
}
];Option 3: Type + Custom Cell (Advanced)
Best for: Custom logic or styling while preserving type formatting
// 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 (
<div style={{
color: rawValue === 'active' ? 'green' : 'red',
fontWeight: 'bold',
padding: '4px 8px',
borderRadius: '4px',
backgroundColor: rawValue === 'active' ? '#e8f5e9' : '#ffebee'
}}>
{formattedValue || rawValue} {/* Use formatted value or fallback */}
</div>
);
};
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
const CustomCell = ({ cell, row }) => {
const value = cell.getValue();
return (
<div className="custom-cell">
<strong>{value}</strong>
<span className="badge">{row.original.count}</span>
</div>
);
};
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:
{
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:
- accessorFn/accessorKey evaluated: Value is extracted from row data
- Type formatter applied: If
typeis specified,DEFAULT_CELL_TYPES[type]processes the value - Content assigned: Formatted value becomes the base
content - Custom Cell receives props: If
Cellis defined, it receives:typeValue: The pre-formatted value- All standard MRT cell props
- CSS wrapper: If
cellClassis defined, final content is wrapped in<div className={cellClass}>
Rendering Priority:
Raw Data → accessorFn → Type Formatter → typeValue → Custom Cell → cellClass Wrapper → Final OutputWhen 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
Example 1: Basic Grid with Selection
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: '[email protected]', role: 'Admin', createdAt: '2024-01-15' },
{ id: 2, name: 'Jane Smith', email: '[email protected]', role: 'User', createdAt: '2024-02-20' },
{ id: 3, name: 'Bob Johnson', email: '[email protected]', role: 'Manager', createdAt: '2024-03-10' },
];
return (
<DataGrid
columns={columns}
createRows={users}
rowKey="id"
selectData={setSelected}
pageSize={50}
itemsPerPage={[25, 50, 100]}
gridHeight={500}
/>
);
}Example 2: Using accessorFn for Complex Data
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 (
<DataGrid
columns={columns}
createRows={conferences}
rowKey="id"
selectData={setSelected}
gridHeight={600}
/>
);
}Example 3: Grid with Actions and Exports
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 (
<DataGrid
columns={columns}
createRows={products}
rowKey="productId"
selectData={setSelectedProducts}
actions={actions}
hasExcelExport={true}
hasPdfExport={true}
gridHeight={600}
/>
);
}Example 3.5: Grid with Filter Actions
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 (
<DataGrid
columns={columns}
createRows={filteredTasks}
rowKey="id"
selectData={setSelected}
filterActions={filterActions}
gridHeight={600}
/>
);
}Example 4: Hierarchical Data with SubRows
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 (
<DataGrid
columns={columns}
createRows={data}
rowKey="id"
selectData={setSelectedItems}
hasSubRows={true}
enableExpanding={true}
gridHeight={500}
/>
);
}Example 5: Custom Styling and Virtualization
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 (
<span style={{
color: getColor(value),
fontWeight: 'bold',
padding: '2px 8px',
borderRadius: '4px',
backgroundColor: `${getColor(value)}22`
}}>
{typeValue || value}
</span>
);
};
const PriorityCell = ({ cell, row }) => {
const priority = cell.getValue();
const icons = {
high: '🔴',
medium: '🟡',
low: '🟢'
};
return (
<span>
{icons[priority]} {priority.toUpperCase()}
</span>
);
};
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 (
<DataGrid
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]}
/>
);
}Example 6: Advanced Features with Cache Management
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 (
<DataGrid
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: (
<div>
<h3>Quick Guide</h3>
<ul>
<li><strong>Selection:</strong> Click rows to select, use checkboxes for multi-select</li>
<li><strong>Filtering:</strong> Use column filters to search specific fields</li>
<li><strong>Global Search:</strong> Search across all columns at once</li>
<li><strong>Sorting:</strong> Click column headers to sort</li>
<li><strong>Export:</strong> Use Excel or PDF buttons to export data</li>
<li><strong>Refresh:</strong> Click cache button to reload latest data</li>
</ul>
<p><strong>Currently showing:</strong> {visibleRowCount} rows</p>
</div>
)
}}
// Display
gridHeight={700}
pageSize={100}
itemsPerPage={[50, 100, 200]}
/>
);
}Example 7: Disabled Rows and Custom Row Styles
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 (
<DataGrid
columns={columns}
createRows={orders}
rowKey="orderId"
selectData={setSelected}
disableRows={getDisabledRows()}
getRowStyle={getRowStyle}
gridHeight={600}
/>
);
}API Reference
Column Definition Object
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
}Action Object
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
}Filter Action Object
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)
}Extra Action Object
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)
}Data Row Object
interface DataRow {
[rowKey: string]: any; // Unique identifier (required)
[key: string]: any; // Other data fields
// Optional: For hierarchical data
subRows?: Array<DataRow>;
isSubRow?: boolean;
}Performance Tips
1. Use Virtualization for Large Datasets
// For 1000+ rows
enableVirtualization={true}2. Optimize Row Height and Compact Mode
// Smaller rows = more visible data
rowHeight={40}
enableCompactStyleMode={true}
fontSize={12}3. Disable Unused Features
// Reduce overhead by disabling features you don't need
enableDensityToggle={false}
enableFullScreenToggle={false}
enableGlobalFilter={false}
enableColumnFilterModes={false}4. Limit Initial Page Size
// Don't render too many rows initially
pageSize={50} // Instead of 150
itemsPerPage={[25, 50, 100]}5. Pre-select Rows Carefully
// Only include necessary IDs
selectedIds={criticalIds} // Instead of selecting all rows6. Optimize Custom Cell Renderers
// 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 <div>{processedValue}</div>;
});7. Keep accessorFn Lightweight
// 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)
}));8. Use Column Visibility Wisely
// Hide columns that aren't immediately needed
columnVisibilityState={{
metadata: false,
internalId: false,
debugInfo: false
}}9. Implement Efficient Row Styling
// Keep getRowStyle lightweight
getRowStyle={({ row }) => {
// Simple conditional - avoid heavy computation
return row.original.isHighlighted ? { backgroundColor: '#fffacd' } : {};
}}10. Batch State Updates
// Instead of multiple state updates, batch them
const handleMultipleChanges = () => {
// Use a single state update with derived values
setData(prevData => processAndUpdate(prevData));
};11. Leverage React's Built-in Optimizations
// 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)
CSS Requirements
- CSS Grid support (all modern browsers)
- CSS Sticky positioning for fixed headers
- Flexbox for layouts
Troubleshooting
Common Issues
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
selectDatacallback is provided - Check that
rowKeymatches your data's unique identifier property - Verify rows aren't in the
disableRowsarray
// Correct configuration
<DataGrid
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-DDorYYYY-MM-DDTHH:mm:ss) - Check that date strings are parseable by JavaScript
Dateconstructor
// 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
gridHeightis 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-headerclass
// Correct fixed header configuration
<DataGrid
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}andenableFixedActions={true} - Verify
gridHeightis set to a specific value - Check for CSS conflicts with
grid-sticky-actionsclass
<DataGrid
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
selectedIdsprop to control selection from parent - Component automatically syncs when
selectedIdsprop changes - Ensure
rowKeyvalues inselectedIdsmatch data
const [externalSelection, setExternalSelection] = useState([1, 5, 10]);
<DataGrid
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/orhasPdfExport={true} - Check that
disableSideActions={false}(default) - Ensure toolbar has space (not too many actions)
- Verify
enableTopToolbar={true}(default)
<DataGrid
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
typeproperty defined - Check that
typevalue exists inDEFAULT_CELL_TYPES(e.g., 'text', 'date', 'currency', 'email') - Ensure data values are in correct format for the type
- Check browser console for errors
// 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 Cell
Solutions:
- Verify column has both
typeANDCelldefined - Check that
typematches a key inDEFAULT_CELL_TYPES typeValueonly exists when type formatter is applied
// Correct configuration for typeValue
const CustomCell = ({ typeValue, cell }) => {
console.log(typeValue); // Will be defined
return <div>{typeValue}</div>;
};
{
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
accessorFnis defined correctly - The returned value from
accessorFnis what gets filtered/sorted - For complex objects, ensure
accessorFnreturns a simple value
// Bad - Returns object (hard to filter/sort)
accessorFn: (row) => ({ value: row.data })
// Good - Returns simple value
accessorFn: (row) => row.data?.value ?? 0Issue: Virtualization causing scroll issues
Symptoms: Jerky scrolling, rows not rendering, blank spaces
Solutions:
- Ensure
rowHeightis 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
// Good for virtualization
<DataGrid
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
selectionModesetting ('single', 'multi', 'always') - Verify
disabledprop isn't set to true - Ensure rows are actually being selected (check
selectDatacallback)
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
subRowsstructure - SubRow IDs should follow pattern:
"parentId.index"
const hierarchicalData = [
{
id: 1,
name: 'Parent',
subRows: [
{ id: '1.1', name: 'Child 1' },
{ id: '1.2', name: 'Child 2' }
]
}
];
<DataGrid
hasSubRows={true}
enableExpanding={true}
createRows={hierarchicalData}
/>Issue: Cache update button not appearing
Symptoms: Cache/refresh button is not visible
Solutions:
- Provide
updateCachefunction prop - Optionally set
cacheUpdateTextfor tooltip - Button only appears when
updateCacheis defined
<DataGrid
updateCache={() => fetchLatestData()}
cacheUpdateText="Refresh from server"
cacheUpdating={isLoading}
/>Issue: Row styles not applying
Symptoms: getRowStyle returns styles but they don't appear
Solutions:
- Check that returned object contains valid CSS properties
- Verify function is actually being called
- CSS specificity might be overriding - use
!importantif needed - Check browser console for CSS errors
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
filterFnis valid - Ensure data values match filter input type
- If using
accessorFn, ensure it returns filterable values
{
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
Row Selection Behavior
- 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
rowSelectionstate andselectDatacallback
Fixed Header and Actions
enableFixedHeaderuses CSSposition: stickyon column headersenableFixedActions(requiresenableFixedHeader={true}) also pins the toolbar- Both require
gridHeightto be set to a specific value (not 'fit-content') - CSS classes:
grid-sticky-headerandgrid-sticky-actions
Date Columns
- Use
type: 'date'for date-only display (no time) - Use
type: 'datetime'for full datetime display - Default locale is 'pt-PT' - override with
localeprop on column - Date values should be ISO 8601 format for best results
accessorFn Performance
accessorFnis 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
LocalizationProvider
- Component is wrapped with MUI's
LocalizationProviderusingAdapterDateFns - Required for date picker functionality in filters
- No need to add this provider in your own code
SubRows and Hierarchical Data
- 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
Performance Considerations
- 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
accessorFncomputations lightweight
Browser Storage
- 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:
Core Dependencies
- 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
Version Compatibility
{
"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"
}
}Built With
- Material React Table - Advanced table features
- MUI (Material-UI) - UI components and theming
- Semantic UI React - Button and icon components
- Bootstrap - CSS utilities
- date-fns - Modern JavaScript date utility library
License
ISC
