@insticc/react-datagrid-2 1.1.19 → 1.1.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,1042 +1,2084 @@
1
- # DataGrid Component
2
-
3
- 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.
4
-
5
- ## Table of Contents
6
-
7
- - [Installation](#installation)
8
- - [Basic Usage](#basic-usage)
9
- - [Props Reference](#props-reference)
10
- - [Core Props](#core-props)
11
- - [Column Configuration](#column-configuration)
12
- - [Actions & Toolbar](#actions--toolbar)
13
- - [Export Options](#export-options)
14
- - [Selection & Interaction](#selection--interaction)
15
- - [Pagination & Display](#pagination--display)
16
- - [Styling & Layout](#styling--layout)
17
- - [Advanced Features](#advanced-features)
18
- - [Column Types](#column-types)
19
- - [Examples](#examples)
20
- - [API Reference](#api-reference)
21
-
22
- ---
23
-
24
- ## Installation
25
-
26
- ```bash
27
- npm install @insticc/react-datagrid-2
28
- ```
29
-
30
- ### Required Dependencies
31
-
32
- ```bash
33
- npm install react prop-types material-react-table semantic-ui-react @mui/material bootstrap
34
- ```
35
-
36
- ---
37
-
38
- ## Basic Usage
39
-
40
- ```jsx
41
- import React, { useState } from 'react';
42
- import { DataGrid } from '@insticc/react-datagrid-2';
43
-
44
- function MyComponent() {
45
- const [selectedRows, setSelectedRows] = useState([]);
46
-
47
- const columns = [
48
- { accessorKey: 'id', header: 'ID', type: 'text' },
49
- { accessorKey: 'name', header: 'Name', type: 'text' },
50
- { accessorKey: 'email', header: 'Email', type: 'email' },
51
- { accessorKey: 'createdAt', header: 'Created', type: 'date', isDateColumn: true },
52
- ];
53
-
54
- const data = [
55
- { id: '1', name: 'John Doe', email: 'john@example.com', createdAt: '2025-01-15' },
56
- { id: '2', name: 'Jane Smith', email: 'jane@example.com', createdAt: '2025-02-20' },
57
- ];
58
-
59
- return (
60
- <DataGrid
61
- columns={columns}
62
- createRows={data}
63
- rowKey="id"
64
- selectData={setSelectedRows}
65
- hasExcelExport={true}
66
- hasPdfExport={true}
67
- />
68
- );
69
- }
70
- ```
71
-
72
- ---
73
-
74
- ## Props Reference
75
-
76
- ### Core Props
77
-
78
- #### `columns` (required)
79
- - **Type:** `Array`
80
- - **Description:** Array of column definitions that determine how data is displayed
81
- - **Example:**
82
- ```jsx
83
- const columns = [
84
- {
85
- accessorKey: 'name', // Key to access data
86
- header: 'Full Name', // Column header text
87
- type: 'text', // Cell type - formatter applied automatically
88
- enableSorting: true, // Enable/disable sorting
89
- enableColumnFilter: true, // Enable/disable filtering
90
- filterFn: 'contains', // Filter function type
91
- isDateColumn: false, // Special handling for dates
92
- cellClass: 'custom-class', // CSS class wrapping cell content
93
- Cell: CustomComponent, // Optional: Custom cell renderer (receives typeValue)
94
- }
95
- ];
96
- ```
97
-
98
- **Column Rendering Modes:**
99
- - `type` only: Formatter applied automatically
100
- - `type` + `cellClass`: Formatted content wrapped in div
101
- - `type` + `Cell`: Custom component receives `typeValue` (formatted content)
102
- - `Cell` only: Full custom rendering without type formatter
103
-
104
- #### `createRows` (required)
105
- - **Type:** `Array`
106
- - **Description:** Array of data objects to display in the grid
107
- - **Example:**
108
- ```jsx
109
- const data = [
110
- { id: 1, name: 'John', email: 'john@example.com' },
111
- { id: 2, name: 'Jane', email: 'jane@example.com' }
112
- ];
113
- ```
114
-
115
- #### `rowKey` (required)
116
- - **Type:** `string`
117
- - **Description:** Property name used as unique identifier for each row
118
- - **Default:** `'id'`
119
- - **Example:** `rowKey="id"` or `rowKey="uuid"`
120
-
121
- #### `selectData` (required)
122
- - **Type:** `function`
123
- - **Description:** Callback function that receives selected rows whenever selection changes
124
- - **Signature:** `(selectedRows: Array) => void`
125
- - **Example:**
126
- ```jsx
127
- const handleSelection = (rows) => {
128
- console.log('Selected rows:', rows);
129
- };
130
-
131
- <DataGrid selectData={handleSelection} />
132
- ```
133
-
134
- ---
135
-
136
- ### Column Configuration
137
-
138
- #### `columnVisibilityState`
139
- - **Type:** `object`
140
- - **Default:** `{}`
141
- - **Description:** Controls which columns are visible/hidden
142
- - **Example:**
143
- ```jsx
144
- columnVisibilityState={{
145
- email: false, // Hide email column
146
- phone: true // Show phone column
147
- }}
148
- ```
149
-
150
- #### `columnOrder`
151
- - **Type:** `Array<string>`
152
- - **Default:** `[]`
153
- - **Description:** Defines the order of columns by their accessorKey
154
- - **Example:**
155
- ```jsx
156
- columnOrder={['name', 'email', 'id']}
157
- ```
158
-
159
- ---
160
-
161
- ### Actions & Toolbar
162
-
163
- #### `actions`
164
- - **Type:** `Array<ActionObject>`
165
- - **Default:** `null`
166
- - **Description:** Array of custom action buttons displayed in the toolbar
167
- - **Action Object Properties:**
168
- - `name` (string): Button label
169
- - `function` (function, required): Callback when button is clicked
170
- - `tooltip` (string): Tooltip text on hover
171
- - `color` (string): Button color - one of: `'blue'`, `'red'`, `'green'`, `'yellow'`, `'orange'`, `'black'`, `'grey'`, `'teal'`, `'brown'`, `'violet'`, `'purple'`, `'olive'`, `'pink'`
172
- - `icon` (string|element): Icon name or React element
173
- - `selectionMode` (string): When button is enabled - `'single'`, `'multi'`, `'always'`
174
- - `confirmMessage` (string|element): Confirmation message before action
175
- - `hasConfirmMessage` (boolean): Whether to show confirmation dialog
176
- - `disabled` (boolean): Disable the button
177
- - `visible` (boolean): Show/hide the button
178
- - `toggle` (boolean): Toggle button style
179
- - `active` (boolean): Toggle button active state
180
- - **Example:**
181
- ```jsx
182
- actions={[
183
- {
184
- name: 'Delete',
185
- function: (selectedRows) => handleDelete(selectedRows),
186
- tooltip: 'Delete selected rows',
187
- color: 'red',
188
- icon: 'trash',
189
- selectionMode: 'multi',
190
- hasConfirmMessage: true,
191
- confirmMessage: 'Are you sure you want to delete these rows?'
192
- },
193
- {
194
- name: 'Edit',
195
- function: (selectedRows) => handleEdit(selectedRows),
196
- tooltip: 'Edit selected row',
197
- color: 'blue',
198
- icon: 'edit',
199
- selectionMode: 'single'
200
- },
201
- {
202
- name: 'Add New',
203
- function: () => handleAdd(),
204
- tooltip: 'Add new record',
205
- color: 'green',
206
- icon: 'plus',
207
- selectionMode: 'always'
208
- }
209
- ]}
210
- ```
211
-
212
- #### `enableTopToolbar`
213
- - **Type:** `boolean`
214
- - **Default:** `true`
215
- - **Description:** Show/hide the top toolbar containing actions and pagination
216
-
217
- #### `enableBottomToolbar`
218
- - **Type:** `boolean`
219
- - **Default:** `false`
220
- - **Description:** Show/hide the bottom toolbar
221
-
222
- #### `hasClearFiltersBtn`
223
- - **Type:** `boolean`
224
- - **Default:** `true`
225
- - **Description:** Show/hide the "Clear Filters" button in toolbar
226
-
227
- #### `gridHelper`
228
- - **Type:** `object | null`
229
- - **Default:** `null`
230
- - **Description:** Adds a help button with custom content
231
- - **Required Properties (if defined):**
232
- - `title` (string|element, required): Help dialog title
233
- - `content` (string|element, required): Help dialog content
234
- - **Example:**
235
- ```jsx
236
- gridHelper={{
237
- title: 'Grid Instructions',
238
- content: (
239
- <div>
240
- <p>Use the filters to search data</p>
241
- <p>Click rows to select them</p>
242
- </div>
243
- )
244
- }}
245
- ```
246
-
247
- ---
248
-
249
- ### Export Options
250
-
251
- #### `hasExcelExport`
252
- - **Type:** `boolean`
253
- - **Default:** `false`
254
- - **Description:** Enable Excel export button
255
-
256
- #### `hasPdfExport`
257
- - **Type:** `boolean`
258
- - **Default:** `false`
259
- - **Description:** Enable PDF export button
260
-
261
- #### `pdfOption`
262
- - **Type:** `string`
263
- - **Default:** `'selectedRows'`
264
- - **Options:** `'all'`, `'allRows'`, `'pageRows'`, `'selectedRows'`
265
- - **Description:** Determines which rows to export to PDF
266
-
267
- **Export Options Explained:**
268
- - `'all'` - Export all data including hidden columns
269
- - `'allRows'` - Export all rows (respects filters)
270
- - `'pageRows'` - Export only current page rows
271
- - `'selectedRows'` - Export only selected rows
272
-
273
- ---
274
-
275
- ### Selection & Interaction
276
-
277
- #### `disableSelect`
278
- - **Type:** `boolean`
279
- - **Default:** `false`
280
- - **Description:** Disable row selection checkboxes and click-to-select behavior completely
281
-
282
- #### `enableMultiRowSelection`
283
- - **Type:** `boolean`
284
- - **Default:** `true`
285
- - **Description:** Allow selecting multiple rows at once
286
-
287
- #### `selectAllMode`
288
- - **Type:** `string`
289
- - **Default:** `'page'`
290
- - **Options:** `'page'`, `'all'`
291
- - **Description:**
292
- - `'page'` - "Select All" checkbox selects only current page
293
- - `'all'` - "Select All" checkbox selects all filtered rows
294
-
295
- #### `selectedIds`
296
- - **Type:** `Array`
297
- - **Default:** `[]`
298
- - **Description:** Array of row IDs that should be pre-selected
299
- - **Example:**
300
- ```jsx
301
- selectedIds={[1, 5, 10]} // Pre-select rows with these IDs
302
- ```
303
-
304
- #### `disableRows`
305
- - **Type:** `Array`
306
- - **Default:** `[]`
307
- - **Description:** Array of row IDs that should be disabled (cannot be selected)
308
- - **Example:**
309
- ```jsx
310
- disableRows={[3, 7]} // Disable selection for these rows
311
- ```
312
-
313
- #### `hasSubRows`
314
- - **Type:** `boolean`
315
- - **Default:** `false`
316
- - **Description:** Enable support for hierarchical/nested rows
317
- - **Note:** Requires data with `subRows` property
318
-
319
- #### `enableExpanding`
320
- - **Type:** `boolean`
321
- - **Default:** `false`
322
- - **Description:** Show expand/collapse icons for rows with subRows
323
-
324
- ---
325
-
326
- ### Pagination & Display
327
-
328
- #### `enablePagination`
329
- - **Type:** `boolean`
330
- - **Default:** `true`
331
- - **Description:** Enable/disable pagination
332
-
333
- #### `pagination`
334
- - **Type:** `string`
335
- - **Default:** `'both'`
336
- - **Options:** `'top'`, `'bottom'`, `'both'`
337
- - **Description:** Position of pagination controls
338
-
339
- #### `pageSize`
340
- - **Type:** `number`
341
- - **Default:** `150`
342
- - **Description:** Number of rows per page initially
343
-
344
- #### `itemsPerPage`
345
- - **Type:** `Array<number>`
346
- - **Default:** `[50, 100, 150]`
347
- - **Description:** Options for rows per page dropdown
348
- - **Example:**
349
- ```jsx
350
- itemsPerPage={[10, 25, 50, 100]}
351
- ```
352
-
353
- ---
354
-
355
- ### Styling & Layout
356
-
357
- #### `rowHeight`
358
- - **Type:** `number`
359
- - **Default:** `75`
360
- - **Description:** Minimum height of each row in pixels
361
-
362
- #### `fontSize`
363
- - **Type:** `number`
364
- - **Default:** `14`
365
- - **Description:** Base font size for grid content in pixels
366
-
367
- #### `gridHeight`
368
- - **Type:** `number | string`
369
- - **Default:** `600`
370
- - **Description:** Maximum height of the grid container
371
- - **Examples:**
372
- ```jsx
373
- gridHeight={600} // 600px
374
- gridHeight="80vh" // 80% of viewport height
375
- gridHeight="fit-content" // Auto height
376
- ```
377
-
378
- #### `enableCompactStyleMode`
379
- - **Type:** `boolean`
380
- - **Default:** `false`
381
- - **Description:** Enable compact styling with reduced padding and responsive font sizes
382
- - **Features:**
383
- - Smaller cell padding (2px vs auto)
384
- - Responsive font sizing using clamp()
385
- - Optimized for dense data display
386
-
387
- #### `getRowStyle`
388
- - **Type:** `function`
389
- - **Description:** Custom function to apply styles to rows based on data
390
- - **Signature:** `({ row }) => object`
391
- - **Example:**
392
- ```jsx
393
- getRowStyle={({ row }) => ({
394
- backgroundColor: row.original.status === 'active' ? '#e8f5e9' : 'white',
395
- color: row.original.priority === 'high' ? 'red' : 'inherit'
396
- })}
397
- ```
398
-
399
- #### `enableFixedHeader`
400
- - **Type:** `boolean`
401
- - **Default:** `true`
402
- - **Description:** Pin headers to top when scrolling
403
-
404
- #### `enableFixedActions`
405
- - **Type:** `boolean`
406
- - **Default:** `false`
407
- - **Description:** Pin action toolbar to top when scrolling (requires enableFixedHeader)
408
-
409
- ---
410
-
411
- ### Advanced Features
412
-
413
- #### `enableGlobalFilter`
414
- - **Type:** `boolean`
415
- - **Default:** `false`
416
- - **Description:** Show global search input that filters all columns
417
-
418
- #### `globalFilterFn`
419
- - **Type:** `string`
420
- - **Default:** `'contains'`
421
- - **Options:** `'contains'`, `'fuzzy'`, `'between'`, `'equals'`, `'greaterThan'`, `'lessThan'`, `'notEquals'`, `'lessThanOrEqualTo'`, `'greaterThanOrEqualTo'`, `'empty'`, `'notEmpty'`, `'startsWith'`, `'endsWith'`, `'betweenInclusive'`
422
- - **Description:** Filter function for global search
423
-
424
- #### `enableColumnFilterModes`
425
- - **Type:** `boolean`
426
- - **Default:** `true`
427
- - **Description:** Allow users to change filter type per column (contains, equals, etc.)
428
-
429
- #### `enableVirtualization`
430
- - **Type:** `boolean`
431
- - **Default:** `false`
432
- - **Description:** Enable row and column virtualization for large datasets (improves performance)
433
- - **Recommended for:** 1000+ rows
434
-
435
- #### `enableFullScreenToggle`
436
- - **Type:** `boolean`
437
- - **Default:** `false`
438
- - **Description:** Show fullscreen toggle button
439
-
440
- #### `enableDensityToggle`
441
- - **Type:** `boolean`
442
- - **Default:** `false`
443
- - **Description:** Show density toggle button (compact/comfortable/spacious)
444
-
445
- ---
446
-
447
- ### Cache & Updates
448
-
449
- #### `updateCache`
450
- - **Type:** `function`
451
- - **Default:** `undefined`
452
- - **Description:** Callback function triggered when cache update button is clicked
453
- - **Example:**
454
- ```jsx
455
- updateCache={() => {
456
- fetchLatestData();
457
- }}
458
- ```
459
-
460
- #### `cacheUpdateText`
461
- - **Type:** `string`
462
- - **Default:** `undefined`
463
- - **Description:** Tooltip text for cache update button
464
- - **Example:** `"Refresh data from server"`
465
-
466
- #### `cacheUpdating`
467
- - **Type:** `boolean`
468
- - **Default:** `false`
469
- - **Description:** Shows loading state on cache update button
470
-
471
- ---
472
-
473
- ### Callbacks
474
-
475
- #### `onVisibleRowsChange`
476
- - **Type:** `function`
477
- - **Description:** Called whenever visible rows change (filtering, sorting, pagination)
478
- - **Signature:** `(visibleRows: Array) => void`
479
- - **Example:**
480
- ```jsx
481
- onVisibleRowsChange={(rows) => {
482
- console.log('Currently visible:', rows.length);
483
- }}
484
- ```
485
-
486
- ---
487
-
488
- ## Column Types
489
-
490
- The DataGrid supports various pre-built cell types via the `type` property in column definitions:
491
-
492
- ### Text Types
493
- - `text` - Plain text
494
- - `textTitle` - Bold text
495
- - `textDescription` - Gray text (#666)
496
- - `textSmall` - Small font text
497
-
498
- ### Date Types
499
- - `date` - Date only (no time)
500
- - `datetime` - Date with time
501
-
502
- ### Number Types
503
- - `number` - Raw number
504
- - `integer` - Rounded integer
505
- - `currency` - EUR currency format (€1,234.56)
506
- - `percentage` - Percentage format (12.34%)
507
-
508
- ### Link Types
509
- - `email` - Clickable mailto link
510
- - `phone` - Clickable tel link
511
- - `link` - External link (opens in new tab)
512
-
513
- ### Complex Types
514
- - `array` - Comma-separated array values
515
- - `json` - Formatted JSON display
516
- - `countryFlag` - Country flag image (requires ISO2 code)
517
- - `persons` - List of persons with "et al." notation
518
-
519
- ### Example with Types
520
-
521
- ```jsx
522
- const columns = [
523
- { accessorKey: 'name', header: 'Name', type: 'textTitle' },
524
- { accessorKey: 'description', header: 'Description', type: 'textDescription' },
525
- { accessorKey: 'email', header: 'Email', type: 'email' },
526
- { accessorKey: 'salary', header: 'Salary', type: 'currency' },
527
- { accessorKey: 'completion', header: 'Progress', type: 'percentage' },
528
- { accessorKey: 'createdAt', header: 'Created', type: 'date', isDateColumn: true },
529
- { accessorKey: 'country', header: 'Country', type: 'countryFlag' },
530
- { accessorKey: 'tags', header: 'Tags', type: 'array' },
531
- ];
532
- ```
533
-
534
- ### Custom Cell Renderers with Type Support
535
-
536
- You have multiple options for cell rendering:
537
-
538
- #### Option 1: Using Type Alone (Simplest)
539
- ```jsx
540
- const columns = [
541
- {
542
- accessorKey: 'price',
543
- header: 'Price',
544
- type: 'currency' // Automatically formatted as currency
545
- }
546
- ];
547
- // No custom Cell needed - formatter is applied automatically
548
- ```
549
-
550
- #### Option 2: Type + cellClass
551
- ```jsx
552
- const columns = [
553
- {
554
- accessorKey: 'status',
555
- header: 'Status',
556
- type: 'text',
557
- cellClass: 'custom-status' // Formatted text wrapped in <div class="custom-status">
558
- }
559
- ];
560
- ```
561
-
562
- #### Option 3: Type + Custom Cell (Advanced)
563
- When you need both formatting AND custom logic:
564
-
565
- ```jsx
566
- // Custom cell that uses the type formatter and adds custom styling
567
- const CustomStatusCell = ({ typeValue, cell, row }) => {
568
- const value = cell.getValue();
569
-
570
- return (
571
- <div style={{
572
- color: value === 'active' ? 'green' : 'red',
573
- fontWeight: 'bold'
574
- }}>
575
- {typeValue || value} {/* Use typeValue (formatted) or fallback to raw value */}
576
- </div>
577
- );
578
- };
579
-
580
- const columns = [
581
- {
582
- accessorKey: 'status',
583
- header: 'Status',
584
- type: 'text', // Formatter is applied first
585
- Cell: CustomStatusCell, // Custom component receives typeValue prop
586
- }
587
- ];
588
- ```
589
-
590
- #### Option 4: Custom Cell Only (No Type)
591
- ```jsx
592
- const CustomCell = ({ cell }) => {
593
- return <strong>{cell.getValue()}</strong>;
594
- };
595
-
596
- const columns = [
597
- {
598
- accessorKey: 'name',
599
- header: 'Name',
600
- Cell: CustomCell // No type - full control over rendering
601
- }
602
- ];
603
- ```
604
-
605
- **How Cell Rendering Works:**
606
- 1. If `type` is specified, `DEFAULT_CELL_TYPES[type]` formatter is applied automatically
607
- 2. If `Cell` component is also provided, it receives all props including `typeValue` (the formatted result)
608
- 3. If `cellClass` is specified, content is wrapped in `<div className={cellClass}>`
609
- 4. Priority: Custom Cell (with typeValue) > Type formatter > Raw value
610
-
611
- **Note:** You can use `type` alone without a custom `Cell` component - the formatter will be applied automatically.
612
-
613
- ---
614
-
615
- ## Examples
616
-
617
- ### Example 1: Basic Grid with Selection
618
-
619
- ```jsx
620
- import React, { useState } from 'react';
621
- import DataGrid from '@insticc/react-datagrid-2';
622
-
623
- function UserGrid() {
624
- const [selected, setSelected] = useState([]);
625
-
626
- const columns = [
627
- { accessorKey: 'id', header: 'ID', type: 'integer' },
628
- { accessorKey: 'name', header: 'Name', type: 'textTitle' },
629
- { accessorKey: 'email', header: 'Email', type: 'email' },
630
- { accessorKey: 'role', header: 'Role', type: 'text' },
631
- ];
632
-
633
- const users = [
634
- { id: 1, name: 'John Doe', email: 'john@company.com', role: 'Admin' },
635
- { id: 2, name: 'Jane Smith', email: 'jane@company.com', role: 'User' },
636
- ];
637
-
638
- return (
639
- <DataGrid
640
- columns={columns}
641
- createRows={users}
642
- rowKey="id"
643
- selectData={setSelected}
644
- pageSize={50}
645
- itemsPerPage={[25, 50, 100]}
646
- />
647
- );
648
- }
649
- ```
650
-
651
- ### Example 2: Grid with Actions and Exports
652
-
653
- ```jsx
654
- function ProductGrid() {
655
- const handleDelete = (rows) => {
656
- const ids = rows.map(r => r.id);
657
- console.log('Deleting:', ids);
658
- };
659
-
660
- const handleEdit = (rows) => {
661
- if (rows.length === 1) {
662
- console.log('Editing:', rows[0]);
663
- }
664
- };
665
-
666
- const actions = [
667
- {
668
- name: 'Delete',
669
- function: handleDelete,
670
- tooltip: 'Delete selected products',
671
- color: 'red',
672
- icon: 'trash',
673
- selectionMode: 'multi',
674
- hasConfirmMessage: true,
675
- confirmMessage: 'Are you sure you want to delete these products?'
676
- },
677
- {
678
- name: 'Edit',
679
- function: handleEdit,
680
- tooltip: 'Edit product',
681
- color: 'blue',
682
- icon: 'edit',
683
- selectionMode: 'single'
684
- }
685
- ];
686
-
687
- return (
688
- <DataGrid
689
- columns={productColumns}
690
- createRows={products}
691
- rowKey="productId"
692
- selectData={setSelected}
693
- actions={actions}
694
- hasExcelExport={true}
695
- hasPdfExport={true}
696
- />
697
- );
698
- }
699
- ```
700
-
701
- ### Example 3: Hierarchical Data with SubRows
702
-
703
- ```jsx
704
- function ProjectGrid() {
705
- const data = [
706
- {
707
- id: 1,
708
- name: 'Project Alpha',
709
- status: 'Active',
710
- subRows: [
711
- { id: '1.1', name: 'Task 1', status: 'Complete' },
712
- { id: '1.2', name: 'Task 2', status: 'In Progress' }
713
- ]
714
- },
715
- {
716
- id: 2,
717
- name: 'Project Beta',
718
- status: 'Planning',
719
- subRows: [
720
- { id: '2.1', name: 'Task 1', status: 'Not Started' }
721
- ]
722
- }
723
- ];
724
-
725
- return (
726
- <DataGrid
727
- columns={projectColumns}
728
- createRows={data}
729
- rowKey="id"
730
- selectData={setSelected}
731
- hasSubRows={true}
732
- enableExpanding={true}
733
- />
734
- );
735
- }
736
- ```
737
-
738
- ### Example 4: Custom Styling and Virtualization
739
-
740
- ```jsx
741
- function LargeDataGrid() {
742
- // Custom cell with type support
743
- const StatusCell = ({ typeValue, cell }) => {
744
- const value = cell.getValue();
745
- const color = value === 'active' ? 'green' : 'red';
746
-
747
- return (
748
- <span style={{ color, fontWeight: 'bold' }}>
749
- {typeValue || value}
750
- </span>
751
- );
752
- };
753
-
754
- const getRowStyle = ({ row }) => {
755
- if (row.original.status === 'error') {
756
- return { backgroundColor: '#ffebee' };
757
- }
758
- if (row.original.priority === 'high') {
759
- return { backgroundColor: '#fff3e0' };
760
- }
761
- return {};
762
- };
763
-
764
- const columns = [
765
- { accessorKey: 'id', header: 'ID', type: 'integer' },
766
- {
767
- accessorKey: 'status',
768
- header: 'Status',
769
- type: 'text', // Formatter applied
770
- Cell: StatusCell // Custom cell receives typeValue
771
- },
772
- { accessorKey: 'name', header: 'Name', type: 'text' },
773
- ];
774
-
775
- return (
776
- <DataGrid
777
- columns={columns}
778
- createRows={largeDataset} // 10000+ rows
779
- rowKey="id"
780
- selectData={setSelected}
781
- enableVirtualization={true}
782
- enableCompactStyleMode={true}
783
- rowHeight={40}
784
- fontSize={12}
785
- gridHeight="calc(100vh - 200px)"
786
- getRowStyle={getRowStyle}
787
- pageSize={100}
788
- />
789
- );
790
- }
791
- ```
792
-
793
- ### Example 5: Advanced Features
794
-
795
- ```jsx
796
- function AdvancedGrid() {
797
- const [cacheLoading, setCacheLoading] = useState(false);
798
-
799
- const refreshData = async () => {
800
- setCacheLoading(true);
801
- await fetchLatestData();
802
- setCacheLoading(false);
803
- };
804
-
805
- const handleVisibleRowsChange = (rows) => {
806
- console.log('Visible rows count:', rows.length);
807
- };
808
-
809
- return (
810
- <DataGrid
811
- columns={columns}
812
- createRows={data}
813
- rowKey="id"
814
- selectData={setSelected}
815
-
816
- // Advanced features
817
- enableGlobalFilter={true}
818
- globalFilterFn="fuzzy"
819
- enableColumnFilterModes={true}
820
- enableFixedHeader={true}
821
- enableFixedActions={true}
822
-
823
- // Cache management
824
- updateCache={refreshData}
825
- cacheUpdateText="Refresh data from server"
826
- cacheUpdating={cacheLoading}
827
-
828
- // Callbacks
829
- onVisibleRowsChange={handleVisibleRowsChange}
830
-
831
- // Help
832
- gridHelper={{
833
- title: 'Data Grid Help',
834
- content: (
835
- <div>
836
- <h3>Features</h3>
837
- <ul>
838
- <li>Click rows to select</li>
839
- <li>Use column filters for search</li>
840
- <li>Export to Excel or PDF</li>
841
- </ul>
842
- </div>
843
- )
844
- }}
845
- />
846
- );
847
- }
848
- ```
849
-
850
- ---
851
-
852
- ## API Reference
853
-
854
- ### Column Definition Object
855
-
856
- ```typescript
857
- {
858
- accessorKey: string; // Required: Key to access data
859
- header: string; // Required: Column header text
860
- type?: string; // Cell type (see Column Types)
861
- enableSorting?: boolean; // Default: true
862
- enableColumnFilter?: boolean; // Default: true
863
- enableColumnFilterModes?: boolean;// Default: true
864
- filterFn?: string; // Default: 'contains'
865
- enableResizing?: boolean; // Default: true
866
- grow?: boolean; // Default: true
867
- enableClickToCopy?: boolean; // Default: false
868
- enableColumnActions?: boolean; // Default: false
869
- isDateColumn?: boolean; // Special date handling
870
- sortingFn?: function; // Custom sorting function
871
- Cell?: Component; // Custom cell renderer (receives typeValue prop)
872
- cellClass?: string; // CSS class wrapping cell content
873
- locale?: string; // Locale for date/number formatting
874
- onlyFlag?: boolean; // For countryFlag type
875
- columnDef?: object; // Additional metadata
876
- }
877
- ```
878
-
879
- **Cell Rendering Priority:**
880
- 1. If `type` is defined: `DEFAULT_CELL_TYPES[type]` formatter is applied first (becomes `content`)
881
- 2. If `Cell` is also defined: Custom component receives `typeValue` (the formatted result) and can override `content`
882
- 3. If only `Cell` is defined (no `type`): Custom component has full control
883
- 4. If `cellClass` is defined: Final content is wrapped in `<div className={cellClass}>`
884
-
885
- **Rendering Flow:**
886
- ```
887
- Raw Value → [type formatter] → content → [Custom Cell] content [cellClass wrapper] Final Output
888
- ```
889
-
890
- ### Action Object
891
-
892
- ```typescript
893
- {
894
- name: string; // Button label
895
- function: (selectedRows) => void; // Required: Click handler
896
- tooltip?: string; // Hover tooltip
897
- color?: string; // Button color
898
- icon?: string | element; // Button icon
899
- selectionMode?: 'single' | 'multi' | 'always';
900
- confirmMessage?: string | element;
901
- hasConfirmMessage?: boolean;
902
- disabled?: boolean;
903
- visible?: boolean;
904
- toggle?: boolean;
905
- active?: boolean;
906
- key?: string; // Unique key for React
907
- }
908
- ```
909
-
910
- ---
911
-
912
- ## Performance Tips
913
-
914
- 1. **Use Virtualization for Large Datasets**
915
- ```jsx
916
- enableVirtualization={true} // For 1000+ rows
917
- ```
918
-
919
- 2. **Optimize Row Height**
920
- ```jsx
921
- rowHeight={40} // Smaller = more rows visible
922
- ```
923
-
924
- 3. **Disable Unused Features**
925
- ```jsx
926
- enableDensityToggle={false}
927
- enableFullScreenToggle={false}
928
- enableGlobalFilter={false}
929
- ```
930
-
931
- 4. **Use Compact Mode**
932
- ```jsx
933
- enableCompactStyleMode={true}
934
- fontSize={12}
935
- ```
936
-
937
- 5. **Limit Initial Page Size**
938
- ```jsx
939
- pageSize={50} // Don't render too many rows initially
940
- ```
941
-
942
- 6. **Pre-select Rows Carefully**
943
- ```jsx
944
- // Only include necessary IDs
945
- selectedIds={criticalIds} // vs selecting all rows
946
- ```
947
-
948
- 7. **Optimize Custom Cell Renderers**
949
- ```jsx
950
- // Use typeValue when available to avoid re-computing
951
- const MyCell = ({ typeValue, cell }) => {
952
- return typeValue || cell.getValue(); // Prefer typeValue
953
- };
954
- ```
955
-
956
- ---
957
-
958
- ## Browser Support
959
-
960
- - Chrome (latest)
961
- - Firefox (latest)
962
- - Safari (latest)
963
- - Edge (latest)
964
-
965
- ---
966
-
967
- ## Important Notes
968
-
969
- ### Row Selection Behavior
970
- - **Click-to-select:** When `disableSelect={false}`, clicking anywhere on a row will toggle its selection
971
- - **Single selection mode:** Clicking a row deselects all other rows and selects only the clicked row
972
- - **Checkbox behavior:** For multi-row selection, use the checkboxes in combination with `enableMultiRowSelection={true}`
973
- - The selection state is controlled by `rowSelection` and updates through the `selectData` callback
974
-
975
- ### Fixed Header and Actions
976
- - `enableFixedHeader` pins the column headers when scrolling
977
- - `enableFixedActions` (requires `enableFixedHeader={true}`) also pins the action toolbar
978
- - Both features use CSS positioning and may require adjustments based on your page layout
979
-
980
- ### Date Columns
981
- - Columns with `isDateColumn={true}` get automatic date-aware sorting
982
- - Use the `type` prop (`'date'` or `'datetime'`) to format date display
983
- - The `locale` prop on columns controls date formatting (default: 'pt-PT')
984
-
985
- ### LocalizationProvider
986
- The DataGrid component is wrapped with MUI's `LocalizationProvider` using `AdapterDateFns`. This is required for any date-related functionality and doesn't need to be added by the consumer.
987
-
988
- ---
989
-
990
- ## Troubleshooting
991
-
992
- ### Common Issues
993
-
994
- **Issue: Rows not selecting when clicked**
995
- - Check that `disableSelect={false}` (default)
996
- - Verify `selectData` callback is provided
997
- - Ensure `rowKey` matches your data's unique identifier
998
-
999
- **Issue: Date columns not sorting correctly**
1000
- - Set `isDateColumn={true}` on date columns
1001
- - Ensure date values are in a valid format (ISO 8601 recommended)
1002
-
1003
- **Issue: Fixed headers not working**
1004
- - Set `enableFixedHeader={true}`
1005
- - Check that `gridHeight` is set to a specific value (not 'fit-content')
1006
- - For fixed actions, also set `enableFixedActions={true}`
1007
-
1008
- **Issue: Selection state not syncing with parent component**
1009
- - Use the `selectedIds` prop to control selection from parent
1010
- - The component will auto-sync when `selectedIds` changes
1011
-
1012
- **Issue: Export buttons not appearing**
1013
- - Set `hasExcelExport={true}` and/or `hasPdfExport={true}`
1014
- - Check that action buttons have enough space in the toolbar
1015
-
1016
- **Issue: Type formatter not working**
1017
- - Verify column has `type` property defined
1018
- - Check that `type` value matches a key in `DEFAULT_CELL_TYPES` (e.g., 'text', 'date', 'currency')
1019
- - The formatter is applied automatically - no `Cell` component needed
1020
- - If using a custom `Cell`, the formatted value is in `typeValue` prop
1021
-
1022
- **Issue: Custom Cell component not receiving typeValue**
1023
- - Verify the column has a `type` property defined
1024
- - Check that `type` matches a key in `DEFAULT_CELL_TYPES`
1025
- - Remember: `typeValue` is only passed when both `type` and `Cell` are defined
1026
-
1027
- ---
1028
-
1029
- ## Dependencies
1030
-
1031
- This component is built on top of:
1032
- - [Material React Table](https://www.material-react-table.com/) - Core table functionality
1033
- - [MUI (Material-UI)](https://mui.com/) - UI components and styling
1034
- - [Semantic UI React](https://react.semantic-ui.com/) - Additional UI components
1035
- - [Bootstrap](https://getbootstrap.com/) - Base CSS framework
1036
- - [date-fns](https://date-fns.org/) - Date manipulation and formatting
1037
-
1038
- ---
1039
-
1040
- ## License
1041
-
1042
- ISC
1
+ # DataGrid Component
2
+
3
+ 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.
4
+
5
+ ## Table of Contents
6
+
7
+ - [Installation](#installation)
8
+ - [Basic Usage](#basic-usage)
9
+ - [Props Reference](#props-reference)
10
+ - [Core Props](#core-props)
11
+ - [Column Configuration](#column-configuration)
12
+ - [Actions & Toolbar](#actions--toolbar)
13
+ - [Export Options](#export-options)
14
+ - [Selection & Interaction](#selection--interaction)
15
+ - [Pagination & Display](#pagination--display)
16
+ - [Styling & Layout](#styling--layout)
17
+ - [Advanced Features](#advanced-features)
18
+ - [Cache & Updates](#cache--updates)
19
+ - [Callbacks](#callbacks)
20
+ - [Column Types](#column-types)
21
+ - [Examples](#examples)
22
+ - [API Reference](#api-reference)
23
+ - [Performance Tips](#performance-tips)
24
+ - [Browser Support](#browser-support)
25
+ - [Troubleshooting](#troubleshooting)
26
+
27
+ ---
28
+
29
+ ## Installation
30
+
31
+ ```bash
32
+ npm install @insticc/react-datagrid-2
33
+ ```
34
+
35
+ ### Required Dependencies
36
+
37
+ ```bash
38
+ npm install react prop-types material-react-table semantic-ui-react @mui/material @mui/x-date-pickers date-fns bootstrap semantic-ui-css
39
+ ```
40
+
41
+ ---
42
+
43
+ ## Basic Usage
44
+
45
+ ```jsx
46
+ import React, { useState } from 'react';
47
+ import { DataGrid } from '@insticc/react-datagrid-2';
48
+
49
+ function MyComponent() {
50
+ const [selectedRows, setSelectedRows] = useState([]);
51
+
52
+ const columns = [
53
+ { accessorKey: 'id', header: 'ID', type: 'text' },
54
+ { accessorKey: 'name', header: 'Name', type: 'text' },
55
+ { accessorKey: 'email', header: 'Email', type: 'email' },
56
+ { accessorKey: 'createdAt', header: 'Created', type: 'date', isDateColumn: true },
57
+ ];
58
+
59
+ const data = [
60
+ { id: '1', name: 'John Doe', email: 'john@example.com', createdAt: '2025-01-15' },
61
+ { id: '2', name: 'Jane Smith', email: 'jane@example.com', createdAt: '2025-02-20' },
62
+ ];
63
+
64
+ return (
65
+ <DataGrid
66
+ columns={columns}
67
+ createRows={data}
68
+ rowKey="id"
69
+ selectData={setSelectedRows}
70
+ hasExcelExport={true}
71
+ hasPdfExport={true}
72
+ />
73
+ );
74
+ }
75
+ ```
76
+
77
+ ---
78
+
79
+ ## Props Reference
80
+
81
+ ### Core Props
82
+
83
+ #### `columns` (required)
84
+ - **Type:** `Array<ColumnDefinition>`
85
+ - **Description:** Array of column definitions that determine how data is displayed
86
+ - **Example:**
87
+ ```jsx
88
+ const columns = [
89
+ {
90
+ accessorKey: 'name', // Key to access data (use with accessorFn or alone)
91
+ header: 'Full Name', // Column header text
92
+ type: 'text', // Cell type - formatter applied automatically
93
+
94
+ // Data Access
95
+ accessorFn: (row) => row.firstName + ' ' + row.lastName,
96
+
97
+ // Filtering & Sorting
98
+ enableSorting: true, // Enable/disable sorting (default: true)
99
+ enableColumnFilter: true, // Enable/disable filtering (default: true)
100
+ enableColumnFilterModes: true, // Allow changing filter modes (default: true)
101
+ filterFn: 'contains', // Filter function type (default: 'contains')
102
+ sortingFn: 'basic', // Sorting function (default: 'basic' or custom for dates)
103
+ isDateColumn: false, // Special handling for dates (default: false)
104
+
105
+ // Display
106
+ cellClass: 'custom-class', // CSS class wrapping cell content
107
+ Cell: CustomComponent, // Optional: Custom cell renderer (receives typeValue)
108
+ enableResizing: true, // Allow column resizing (default: true)
109
+ grow: true, // Column can grow (default: true)
110
+ enableClickToCopy: false, // Enable click-to-copy (default: false)
111
+ enableColumnActions: false, // Show column actions menu (default: false)
112
+ }
113
+ ];
114
+ ```
115
+
116
+ **Column Rendering Modes:**
117
+ - `type` only: Formatter applied automatically
118
+ - `type` + `cellClass`: Formatted content wrapped in div with CSS class
119
+ - `type` + `Cell`: Custom component receives `typeValue` (formatted content) as prop
120
+ - `Cell` only: Full custom rendering without type formatter
121
+
122
+ #### `createRows` (required)
123
+ - **Type:** `Array<Object>`
124
+ - **Description:** Array of data objects to display in the grid
125
+ - **Example:**
126
+ ```jsx
127
+ const data = [
128
+ { id: 1, name: 'John', email: 'john@example.com' },
129
+ { id: 2, name: 'Jane', email: 'jane@example.com' }
130
+ ];
131
+ ```
132
+
133
+ #### `rowKey` (required)
134
+ - **Type:** `string`
135
+ - **Description:** Property name used as unique identifier for each row
136
+ - **Example:** `rowKey="id"` or `rowKey="uuid"`
137
+
138
+ #### `selectData` (required)
139
+ - **Type:** `function`
140
+ - **Description:** Callback function that receives selected rows whenever selection changes
141
+ - **Signature:** `(selectedRows: Array<Object>) => void`
142
+ - **Example:**
143
+ ```jsx
144
+ const handleSelection = (rows) => {
145
+ console.log('Selected rows:', rows);
146
+ console.log('Selected IDs:', rows.map(r => r.id));
147
+ };
148
+
149
+ <DataGrid selectData={handleSelection} />
150
+ ```
151
+
152
+ ---
153
+
154
+ ### Column Configuration
155
+
156
+ #### Understanding `accessorKey` vs `accessorFn`
157
+
158
+ The DataGrid provides two ways to access data from your rows:
159
+
160
+ ##### `accessorKey` (Simple Access)
161
+ - **Type:** `string`
162
+ - **Use when:** You want to access a property directly from the row object
163
+ - **Example:**
164
+ ```jsx
165
+ {
166
+ accessorKey: 'name', // Accesses row.name
167
+ header: 'Name'
168
+ }
169
+ ```
170
+
171
+ ##### `accessorFn` (Custom Access)
172
+ - **Type:** `(row: Object) => any`
173
+ - **Use when:** You need to compute or transform the value from row data
174
+ - **Receives:** The complete row object as parameter
175
+ - **Returns:** The value to be used for display, filtering, and sorting
176
+ - **Priority:** Overrides `accessorKey` if both are defined
177
+ - **Examples:**
178
+
179
+ ```jsx
180
+ // Example 1: Handle null/undefined values with fallback
181
+ {
182
+ accessorKey: 'acronym',
183
+ accessorFn: (row) => row.acronym ?? '',
184
+ header: 'Acronym',
185
+ type: 'text'
186
+ }
187
+
188
+ // Example 2: Access nested object properties
189
+ {
190
+ accessorKey: 'paperCount',
191
+ accessorFn: (row) => row.numberPapers?.value ?? 0,
192
+ header: 'Papers',
193
+ type: 'integer'
194
+ }
195
+
196
+ // Example 3: Combine multiple fields
197
+ {
198
+ accessorKey: 'fullName',
199
+ accessorFn: (row) => `${row.firstName} ${row.lastName}`,
200
+ header: 'Full Name',
201
+ type: 'text'
202
+ }
203
+
204
+ // Example 4: Conditional logic
205
+ {
206
+ accessorKey: 'status',
207
+ accessorFn: (row) => row.isActive ? 'Active' : 'Inactive',
208
+ header: 'Status',
209
+ type: 'text'
210
+ }
211
+
212
+ // Example 5: Complex calculations
213
+ {
214
+ accessorKey: 'total',
215
+ accessorFn: (row) => (row.price || 0) * (row.quantity || 0),
216
+ header: 'Total',
217
+ type: 'currency'
218
+ }
219
+
220
+ // Example 6: Array to string conversion
221
+ {
222
+ accessorKey: 'tags',
223
+ accessorFn: (row) => row.tags?.join(', ') ?? 'No tags',
224
+ header: 'Tags',
225
+ type: 'text'
226
+ }
227
+
228
+ // Example 7: Date formatting for sorting
229
+ {
230
+ accessorKey: 'createdDate',
231
+ accessorFn: (row) => row.createdAt ? new Date(row.createdAt).getTime() : 0,
232
+ header: 'Created',
233
+ type: 'date',
234
+ isDateColumn: true
235
+ }
236
+ ```
237
+
238
+ **Important Notes:**
239
+ - `accessorFn` is executed for **every cell render, filter, and sort operation**
240
+ - Keep the function lightweight to avoid performance issues
241
+ - The returned value is what gets filtered and sorted (not the original cell display)
242
+ - When using `accessorFn`, you typically still need `accessorKey` as a unique identifier for the column
243
+ - `accessorFn` value is passed to the type formatter (if `type` is specified)
244
+
245
+ **Performance Tip:**
246
+ ```jsx
247
+ // Bad - Creates new object every time
248
+ accessorFn: (row) => ({ value: row.data, label: row.name })
249
+
250
+ // Good - Returns simple value
251
+ accessorFn: (row) => row.data?.value ?? 0
252
+ ```
253
+
254
+ #### `columnVisibilityState`
255
+ - **Type:** `object`
256
+ - **Default:** `{}`
257
+ - **Description:** Controls which columns are visible/hidden
258
+ - **Example:**
259
+ ```jsx
260
+ columnVisibilityState={{
261
+ email: false, // Hide email column
262
+ phone: true, // Show phone column
263
+ id: false // Hide ID column
264
+ }}
265
+ ```
266
+
267
+ #### `columnOrder`
268
+ - **Type:** `Array<string>`
269
+ - **Default:** `[]`
270
+ - **Description:** Defines the order of columns by their accessorKey
271
+ - **Example:**
272
+ ```jsx
273
+ columnOrder={['name', 'email', 'createdAt', 'id']}
274
+ ```
275
+
276
+ ---
277
+
278
+ ### Actions & Toolbar
279
+
280
+ #### `actions`
281
+ - **Type:** `Array<ActionObject>`
282
+ - **Default:** `null`
283
+ - **Description:** Array of custom action buttons displayed in the toolbar
284
+ - **Action Object Properties:**
285
+ - `name` (string): Button label
286
+ - `function` (function, required): Callback when button is clicked - receives selected rows or table instance
287
+ - `tooltip` (string): Tooltip text on hover
288
+ - `color` (string): Button color - one of: `'blue'`, `'red'`, `'green'`, `'yellow'`, `'orange'`, `'black'`, `'grey'`, `'teal'`, `'brown'`, `'violet'`, `'purple'`, `'olive'`, `'pink'`
289
+ - `icon` (string|element): Icon name (Semantic UI) or React element
290
+ - `selectionMode` (string): When button is enabled:
291
+ - `'single'` - Enabled only when exactly one row is selected
292
+ - `'multi'` - Enabled when one or more rows are selected
293
+ - `'always'` - Always enabled regardless of selection
294
+ - `confirmMessage` (string|element): Confirmation message before action executes
295
+ - `hasConfirmMessage` (boolean): Whether to show confirmation dialog
296
+ - `disabled` (boolean): Manually disable the button
297
+ - `visible` (boolean): Show/hide the button (default: true)
298
+ - `toggle` (boolean): Render as toggle button
299
+ - `active` (boolean): Toggle button active state (when toggle: true)
300
+ - `key` (string): Unique React key (defaults to name)
301
+ - **Example:**
302
+ ```jsx
303
+ actions={[
304
+ {
305
+ name: 'Delete',
306
+ function: (selectedRows) => handleDelete(selectedRows),
307
+ tooltip: 'Delete selected rows',
308
+ color: 'red',
309
+ icon: 'trash',
310
+ selectionMode: 'multi',
311
+ hasConfirmMessage: true,
312
+ confirmMessage: 'Are you sure you want to delete these rows?'
313
+ },
314
+ {
315
+ name: 'Edit',
316
+ function: (selectedRows) => handleEdit(selectedRows[0]),
317
+ tooltip: 'Edit selected row',
318
+ color: 'blue',
319
+ icon: 'edit',
320
+ selectionMode: 'single'
321
+ },
322
+ {
323
+ name: 'Add New',
324
+ function: () => handleAdd(),
325
+ tooltip: 'Add new record',
326
+ color: 'green',
327
+ icon: 'plus',
328
+ selectionMode: 'always'
329
+ },
330
+ {
331
+ name: 'Archive Mode',
332
+ function: () => toggleArchiveMode(),
333
+ tooltip: 'Toggle archive view',
334
+ color: 'grey',
335
+ icon: 'archive',
336
+ toggle: true,
337
+ active: isArchiveMode,
338
+ selectionMode: 'always'
339
+ }
340
+ ]}
341
+ ```
342
+
343
+ #### `extraActions`
344
+ - **Type:** `Array<ExtraActionObject>`
345
+ - **Default:** `null`
346
+ - **Description:** Additional custom action buttons displayed on the right side of the toolbar
347
+ - **Extra Action Object Properties:**
348
+ - `function` (function, required): Callback when button is clicked
349
+ - `content` (string|element, required): Button content/label
350
+ - `tooltip` (string): Tooltip text on hover
351
+ - `icon` (string|element): Icon name or React element
352
+ - `style` (object): Custom CSS styles for the button
353
+ - `propsButton` (object): Additional props passed to Semantic UI Button component
354
+ - **Example:**
355
+ ```jsx
356
+ extraActions={[
357
+ {
358
+ function: () => openSettings(),
359
+ content: 'Settings',
360
+ tooltip: 'Open settings',
361
+ icon: 'setting',
362
+ style: { backgroundColor: '#f0f0f0' }
363
+ },
364
+ {
365
+ function: () => downloadReport(),
366
+ content: 'Download',
367
+ tooltip: 'Download report',
368
+ icon: 'download',
369
+ propsButton: { loading: isDownloading }
370
+ }
371
+ ]}
372
+ ```
373
+
374
+ #### `enableTopToolbar`
375
+ - **Type:** `boolean`
376
+ - **Default:** `true`
377
+ - **Description:** Show/hide the top toolbar containing actions and pagination
378
+
379
+ #### `enableBottomToolbar`
380
+ - **Type:** `boolean`
381
+ - **Default:** `false`
382
+ - **Description:** Show/hide the bottom toolbar
383
+
384
+ #### `hasClearFiltersBtn`
385
+ - **Type:** `boolean`
386
+ - **Default:** `true`
387
+ - **Description:** Show/hide the "Clear Filters" button in toolbar
388
+
389
+ #### `hasClearSelectionBtn`
390
+ - **Type:** `boolean`
391
+ - **Default:** `true`
392
+ - **Description:** Show/hide the "Clear Selection" button in toolbar
393
+ - **Note:** Only visible when `disableSelect={false}` or `disableRows` array has items
394
+
395
+ #### `disableAllActions`
396
+ - **Type:** `boolean`
397
+ - **Default:** `false`
398
+ - **Description:** Hide all action buttons in the top toolbar
399
+
400
+ #### `disableSideActions`
401
+ - **Type:** `boolean`
402
+ - **Default:** `false`
403
+ - **Description:** Hide side action buttons (export, cache, clear filters, help) while keeping main actions visible
404
+
405
+ #### `gridHelper`
406
+ - **Type:** `object | null`
407
+ - **Default:** `null`
408
+ - **Description:** Adds a help button with custom content in a modal dialog
409
+ - **Required Properties (if defined):**
410
+ - `title` (string|element, required): Help dialog title
411
+ - `content` (string|element, required): Help dialog content
412
+ - **Example:**
413
+ ```jsx
414
+ gridHelper={{
415
+ title: 'Grid Instructions',
416
+ content: (
417
+ <div>
418
+ <h3>How to use this grid:</h3>
419
+ <ul>
420
+ <li>Use the filters above each column to search data</li>
421
+ <li>Click rows to select them</li>
422
+ <li>Use action buttons to perform operations</li>
423
+ <li>Export data using the Excel or PDF buttons</li>
424
+ </ul>
425
+ </div>
426
+ )
427
+ }}
428
+ ```
429
+
430
+ ---
431
+
432
+ ### Export Options
433
+
434
+ #### `hasExcelExport`
435
+ - **Type:** `boolean`
436
+ - **Default:** `false`
437
+ - **Description:** Enable Excel export button in the toolbar
438
+
439
+ #### `hasPdfExport`
440
+ - **Type:** `boolean`
441
+ - **Default:** `false`
442
+ - **Description:** Enable PDF export button in the toolbar
443
+
444
+ **Export Behavior:**
445
+ - Both export buttons are rendered by the `ExportActions` component
446
+ - Exports respect current filters and column visibility
447
+ - Selected rows can be exported if selection is enabled
448
+ - Export filename is auto-generated or can be customized
449
+
450
+ ---
451
+
452
+ ### Selection & Interaction
453
+
454
+ #### `disableSelect`
455
+ - **Type:** `boolean`
456
+ - **Default:** `false`
457
+ - **Description:** Completely disable row selection checkboxes and click-to-select behavior
458
+
459
+ #### `enableMultiRowSelection`
460
+ - **Type:** `boolean`
461
+ - **Default:** `true`
462
+ - **Description:** Allow selecting multiple rows at once
463
+ - **Behavior:**
464
+ - `true` - Users can select multiple rows using checkboxes or Shift+Click
465
+ - `false` - Only one row can be selected at a time
466
+
467
+ #### `selectAllMode`
468
+ - **Type:** `string`
469
+ - **Default:** `'page'`
470
+ - **Options:** `'page'`, `'all'`
471
+ - **Description:**
472
+ - `'page'` - "Select All" checkbox selects only rows on current page
473
+ - `'all'` - "Select All" checkbox selects all filtered rows across all pages
474
+
475
+ #### `selectedIds`
476
+ - **Type:** `Array`
477
+ - **Default:** `[]`
478
+ - **Description:** Array of row IDs that should be pre-selected when grid loads
479
+ - **Example:**
480
+ ```jsx
481
+ selectedIds={[1, 5, 10]} // Pre-select rows with these IDs
482
+ ```
483
+ - **Note:** Component syncs automatically when this prop changes
484
+
485
+ #### `disableRows`
486
+ - **Type:** `Array`
487
+ - **Default:** `[]`
488
+ - **Description:** Array of row IDs (based on `rowKey`) that should be disabled and cannot be selected
489
+ - **Example:**
490
+ ```jsx
491
+ disableRows={[3, 7, 9]} // Disable selection for these row IDs
492
+ ```
493
+ - **Visual:** Disabled rows are shown with gray background (`#e3e3e3`)
494
+
495
+ #### `hasSubRows`
496
+ - **Type:** `boolean`
497
+ - **Default:** `false`
498
+ - **Description:** Enable support for hierarchical/nested rows
499
+ - **Requirements:** Data must include `subRows` property for parent rows
500
+ - **Example Data:**
501
+ ```jsx
502
+ const data = [
503
+ {
504
+ id: 1,
505
+ name: 'Parent Row',
506
+ subRows: [
507
+ { id: '1.1', name: 'Child Row 1' },
508
+ { id: '1.2', name: 'Child Row 2' }
509
+ ]
510
+ }
511
+ ];
512
+ ```
513
+
514
+ #### `enableExpanding`
515
+ - **Type:** `boolean`
516
+ - **Default:** `false`
517
+ - **Description:** Show expand/collapse icons for rows with subRows
518
+ - **Requires:** `hasSubRows={true}`
519
+
520
+ ---
521
+
522
+ ### Pagination & Display
523
+
524
+ #### `enablePagination`
525
+ - **Type:** `boolean`
526
+ - **Default:** `true`
527
+ - **Description:** Enable/disable pagination controls
528
+
529
+ #### `pagination`
530
+ - **Type:** `string`
531
+ - **Default:** `'both'`
532
+ - **Options:** `'top'`, `'bottom'`, `'both'`
533
+ - **Description:** Position of pagination controls
534
+ - **Note:** When using `'top'`, pagination is integrated into the top toolbar
535
+
536
+ #### `pageSize`
537
+ - **Type:** `number`
538
+ - **Default:** `150`
539
+ - **Description:** Number of rows displayed per page initially
540
+
541
+ #### `itemsPerPage`
542
+ - **Type:** `Array<number>`
543
+ - **Default:** `[50, 100, 150]`
544
+ - **Description:** Options available in the rows-per-page dropdown
545
+ - **Example:**
546
+ ```jsx
547
+ itemsPerPage={[10, 25, 50, 100, 200]}
548
+ ```
549
+
550
+ ---
551
+
552
+ ### Styling & Layout
553
+
554
+ #### `rowHeight`
555
+ - **Type:** `number`
556
+ - **Default:** `75`
557
+ - **Description:** Minimum height of each row in pixels
558
+
559
+ #### `fontSize`
560
+ - **Type:** `number`
561
+ - **Default:** `14`
562
+ - **Description:** Base font size for grid content in pixels
563
+ - **Compact Mode:** When `enableCompactStyleMode={true}`, responsive sizing is used: `clamp(fontSize-3px, 1.1vw, fontSize)`
564
+
565
+ #### `gridHeight`
566
+ - **Type:** `number | string`
567
+ - **Default:** `600`
568
+ - **Description:** Maximum height of the grid container
569
+ - **Examples:**
570
+ ```jsx
571
+ gridHeight={600} // 600px fixed height
572
+ gridHeight="80vh" // 80% of viewport height
573
+ gridHeight="calc(100vh - 200px)" // Dynamic height calculation
574
+ ```
575
+
576
+ #### `enableCompactStyleMode`
577
+ - **Type:** `boolean`
578
+ - **Default:** `false`
579
+ - **Description:** Enable compact styling with reduced padding and responsive font sizes
580
+ - **Features:**
581
+ - Reduced cell padding (2px vs auto)
582
+ - Responsive font sizing using CSS clamp()
583
+ - Tighter filter input heights (17px vs default)
584
+ - Reduced column header spacing
585
+ - Optimized for displaying dense data
586
+
587
+ #### `getRowStyle`
588
+ - **Type:** `function`
589
+ - **Description:** Custom function to apply conditional styles to rows based on data
590
+ - **Signature:** `({ row }) => object`
591
+ - **Example:**
592
+ ```jsx
593
+ getRowStyle={({ row }) => {
594
+ const styles = {};
595
+
596
+ if (row.original.status === 'active') {
597
+ styles.backgroundColor = '#e8f5e9';
598
+ }
599
+
600
+ if (row.original.priority === 'high') {
601
+ styles.color = 'red';
602
+ styles.fontWeight = 'bold';
603
+ }
604
+
605
+ if (row.original.isExpired) {
606
+ styles.opacity = 0.6;
607
+ styles.textDecoration = 'line-through';
608
+ }
609
+
610
+ return styles;
611
+ }}
612
+ ```
613
+
614
+ #### `enableFixedHeader`
615
+ - **Type:** `boolean`
616
+ - **Default:** `true`
617
+ - **Description:** Pin column headers to top when scrolling vertically
618
+ - **Implementation:** Uses CSS sticky positioning with class `grid-sticky-header`
619
+
620
+ #### `enableFixedActions`
621
+ - **Type:** `boolean`
622
+ - **Default:** `false`
623
+ - **Description:** Pin action toolbar to top when scrolling
624
+ - **Requires:** `enableFixedHeader={true}`
625
+ - **Implementation:** Uses CSS sticky positioning with class `grid-sticky-actions`
626
+
627
+ ---
628
+
629
+ ### Advanced Features
630
+
631
+ #### `enableGlobalFilter`
632
+ - **Type:** `boolean`
633
+ - **Default:** `false`
634
+ - **Description:** Show global search input that filters across all columns
635
+
636
+ #### `globalFilterFn`
637
+ - **Type:** `string`
638
+ - **Default:** `'contains'`
639
+ - **Options:** `'contains'`, `'fuzzy'`, `'between'`, `'equals'`, `'greaterThan'`, `'lessThan'`, `'notEquals'`, `'lessThanOrEqualTo'`, `'greaterThanOrEqualTo'`, `'empty'`, `'notEmpty'`, `'startsWith'`, `'endsWith'`, `'betweenInclusive'`
640
+ - **Description:** Filter function used for global search
641
+
642
+ #### `enableColumnFilterModes`
643
+ - **Type:** `boolean`
644
+ - **Default:** `true`
645
+ - **Description:** Allow users to change filter type per column (contains, equals, regex, etc.)
646
+ - **Available Modes:** Rendered through `ColumnFilter` component
647
+
648
+ #### `enableVirtualization`
649
+ - **Type:** `boolean`
650
+ - **Default:** `false`
651
+ - **Description:** Enable row and column virtualization for large datasets
652
+ - **Recommended:** For grids with 1000+ rows
653
+ - **Configuration:**
654
+ - Row virtualizer: `overscan: 5`
655
+ - Column virtualizer: `overscan: columns.length`
656
+ - Scroll-to-top on sort change
657
+
658
+ #### `enableFullScreenToggle`
659
+ - **Type:** `boolean`
660
+ - **Default:** `false`
661
+ - **Description:** Show fullscreen toggle button in toolbar
662
+
663
+ #### `enableDensityToggle`
664
+ - **Type:** `boolean`
665
+ - **Default:** `false`
666
+ - **Description:** Show density toggle button (compact/comfortable/spacious)
667
+
668
+ ---
669
+
670
+ ### Cache & Updates
671
+
672
+ #### `updateCache`
673
+ - **Type:** `function`
674
+ - **Default:** `undefined`
675
+ - **Description:** Callback function triggered when cache update button is clicked
676
+ - **Signature:** `() => void`
677
+ - **Example:**
678
+ ```jsx
679
+ updateCache={() => {
680
+ fetchLatestData();
681
+ }}
682
+ ```
683
+ - **Note:** Cache button only appears when this prop is provided
684
+
685
+ #### `cacheUpdateText`
686
+ - **Type:** `string`
687
+ - **Default:** `undefined`
688
+ - **Description:** Tooltip text displayed on hover over the cache update button
689
+ - **Example:** `"Refresh data from server"`
690
+
691
+ #### `cacheUpdating`
692
+ - **Type:** `boolean`
693
+ - **Default:** `false`
694
+ - **Description:** Shows loading state on cache update button
695
+ - **Visual:** Changes button icon to loading spinner
696
+ - **Disables:** Button is disabled while `true`
697
+
698
+ ---
699
+
700
+ ### Callbacks
701
+
702
+ #### `onVisibleRowsChange`
703
+ - **Type:** `function`
704
+ - **Description:** Called whenever the visible rows change (filtering, sorting, pagination)
705
+ - **Signature:** `(visibleRows: Array<Object>) => void`
706
+ - **Example:**
707
+ ```jsx
708
+ onVisibleRowsChange={(rows) => {
709
+ console.log('Currently visible:', rows.length);
710
+ updateDashboardStats(rows);
711
+ }}
712
+ ```
713
+
714
+ ---
715
+
716
+ ## Column Types
717
+
718
+ 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.
719
+
720
+ ### Text Types
721
+ - **`text`** - Plain text display
722
+ - **`textTitle`** - Bold text (font-weight: bold)
723
+ - **`textDescription`** - Gray text (#666666)
724
+ - **`textSmall`** - Small font size text
725
+
726
+ ### Date Types
727
+ - **`date`** - Date only (no time) - Format: locale-specific date
728
+ - **`datetime`** - Date with time - Format: locale-specific datetime
729
+
730
+ ### Number Types
731
+ - **`number`** - Raw number display
732
+ - **`integer`** - Rounded integer (Math.round)
733
+ - **`currency`** - EUR currency format (€1,234.56)
734
+ - **`percentage`** - Percentage format (12.34%)
735
+
736
+ ### Link Types
737
+ - **`email`** - Clickable mailto link (`<a href="mailto:...">`)
738
+ - **`phone`** - Clickable tel link (`<a href="tel:...">`)
739
+ - **`link`** - External link that opens in new tab (`target="_blank"`)
740
+
741
+ ### Complex Types
742
+ - **`array`** - Comma-separated array values
743
+ - **`json`** - Formatted JSON display with indentation
744
+ - **`countryFlag`** - Country flag image (requires ISO2 country code)
745
+ - **`persons`** - List of persons with "et al." for 3+ people
746
+
747
+ ### Example with Types
748
+
749
+ ```jsx
750
+ const columns = [
751
+ { accessorKey: 'name', header: 'Name', type: 'textTitle' },
752
+ { accessorKey: 'description', header: 'Description', type: 'textDescription' },
753
+ { accessorKey: 'email', header: 'Email', type: 'email' },
754
+ { accessorKey: 'phone', header: 'Phone', type: 'phone' },
755
+ { accessorKey: 'website', header: 'Website', type: 'link' },
756
+ { accessorKey: 'salary', header: 'Salary', type: 'currency' },
757
+ { accessorKey: 'completion', header: 'Progress', type: 'percentage' },
758
+ { accessorKey: 'createdAt', header: 'Created', type: 'date', isDateColumn: true },
759
+ { accessorKey: 'lastUpdated', header: 'Last Updated', type: 'datetime', isDateColumn: true },
760
+ { accessorKey: 'country', header: 'Country', type: 'countryFlag' },
761
+ { accessorKey: 'tags', header: 'Tags', type: 'array' },
762
+ { accessorKey: 'metadata', header: 'Metadata', type: 'json' },
763
+ { accessorKey: 'authors', header: 'Authors', type: 'persons' },
764
+ ];
765
+ ```
766
+
767
+ ### Custom Cell Renderers with Type Support
768
+
769
+ You have multiple options for cell rendering, each serving different use cases:
770
+
771
+ #### Option 1: Using Type Alone (Simplest)
772
+ Best for: Standard formatting without custom logic
773
+ ```jsx
774
+ const columns = [
775
+ {
776
+ accessorKey: 'price',
777
+ header: 'Price',
778
+ type: 'currency' // Automatically formatted as €1,234.56
779
+ }
780
+ ];
781
+ // No custom Cell needed - formatter is applied automatically
782
+ ```
783
+
784
+ #### Option 2: Type + cellClass
785
+ Best for: Adding CSS styling to formatted content
786
+ ```jsx
787
+ const columns = [
788
+ {
789
+ accessorKey: 'status',
790
+ header: 'Status',
791
+ type: 'text',
792
+ cellClass: 'status-badge' // Formatted text wrapped in <div class="status-badge">
793
+ }
794
+ ];
795
+ ```
796
+
797
+ #### Option 3: Type + Custom Cell (Advanced)
798
+ Best for: Custom logic or styling while preserving type formatting
799
+ ```jsx
800
+ // Custom cell that uses the type formatter and adds custom styling
801
+ const CustomStatusCell = ({ typeValue, cell, row }) => {
802
+ const rawValue = cell.getValue();
803
+ const formattedValue = typeValue; // Pre-formatted by type formatter
804
+
805
+ return (
806
+ <div style={{
807
+ color: rawValue === 'active' ? 'green' : 'red',
808
+ fontWeight: 'bold',
809
+ padding: '4px 8px',
810
+ borderRadius: '4px',
811
+ backgroundColor: rawValue === 'active' ? '#e8f5e9' : '#ffebee'
812
+ }}>
813
+ {formattedValue || rawValue} {/* Use formatted value or fallback */}
814
+ </div>
815
+ );
816
+ };
817
+
818
+ const columns = [
819
+ {
820
+ accessorKey: 'status',
821
+ header: 'Status',
822
+ type: 'text', // Formatter is applied first
823
+ Cell: CustomStatusCell, // Custom component receives typeValue prop
824
+ }
825
+ ];
826
+ ```
827
+
828
+ #### Option 4: Custom Cell Only (No Type)
829
+ Best for: Complete custom rendering without any formatter
830
+ ```jsx
831
+ const CustomCell = ({ cell, row }) => {
832
+ const value = cell.getValue();
833
+
834
+ return (
835
+ <div className="custom-cell">
836
+ <strong>{value}</strong>
837
+ <span className="badge">{row.original.count}</span>
838
+ </div>
839
+ );
840
+ };
841
+
842
+ const columns = [
843
+ {
844
+ accessorKey: 'name',
845
+ header: 'Name',
846
+ Cell: CustomCell // No type - full control over rendering
847
+ }
848
+ ];
849
+ ```
850
+
851
+ #### Custom Cell Props Reference
852
+
853
+ When using a custom `Cell` component, you receive these props:
854
+
855
+ ```typescript
856
+ {
857
+ cell: Object, // MRT cell instance
858
+ row: Object, // MRT row instance
859
+ table: Object, // MRT table instance
860
+ typeValue: any, // Formatted value from type formatter (if type is defined)
861
+ // Standard MRT props...
862
+ }
863
+ ```
864
+
865
+ **Important:** Access `row.original` to get the original data object.
866
+
867
+ ---
868
+
869
+ **How Cell Rendering Works:**
870
+
871
+ 1. **accessorFn/accessorKey evaluated:** Value is extracted from row data
872
+ 2. **Type formatter applied:** If `type` is specified, `DEFAULT_CELL_TYPES[type]` processes the value
873
+ 3. **Content assigned:** Formatted value becomes the base `content`
874
+ 4. **Custom Cell receives props:** If `Cell` is defined, it receives:
875
+ - `typeValue`: The pre-formatted value
876
+ - All standard MRT cell props
877
+ 5. **CSS wrapper:** If `cellClass` is defined, final content is wrapped in `<div className={cellClass}>`
878
+
879
+ **Rendering Priority:**
880
+ ```
881
+ Raw Data accessorFn Type Formatter typeValue Custom Cell cellClass Wrapper → Final Output
882
+ ```
883
+
884
+ **When to use each approach:**
885
+ - Use **type only** for standard formatting (95% of cases)
886
+ - Use **type + cellClass** for simple styling needs
887
+ - Use **type + Cell** when you need formatting AND custom logic
888
+ - Use **Cell only** for completely custom rendering
889
+
890
+ ---
891
+
892
+ ## Examples
893
+
894
+ ### Example 1: Basic Grid with Selection
895
+
896
+ ```jsx
897
+ import React, { useState } from 'react';
898
+ import DataGrid from '@insticc/react-datagrid-2';
899
+
900
+ function UserGrid() {
901
+ const [selected, setSelected] = useState([]);
902
+
903
+ const columns = [
904
+ { accessorKey: 'id', header: 'ID', type: 'integer' },
905
+ { accessorKey: 'name', header: 'Name', type: 'textTitle' },
906
+ { accessorKey: 'email', header: 'Email', type: 'email' },
907
+ { accessorKey: 'role', header: 'Role', type: 'text' },
908
+ { accessorKey: 'createdAt', header: 'Joined', type: 'date', isDateColumn: true },
909
+ ];
910
+
911
+ const users = [
912
+ { id: 1, name: 'John Doe', email: 'john@company.com', role: 'Admin', createdAt: '2024-01-15' },
913
+ { id: 2, name: 'Jane Smith', email: 'jane@company.com', role: 'User', createdAt: '2024-02-20' },
914
+ { id: 3, name: 'Bob Johnson', email: 'bob@company.com', role: 'Manager', createdAt: '2024-03-10' },
915
+ ];
916
+
917
+ return (
918
+ <DataGrid
919
+ columns={columns}
920
+ createRows={users}
921
+ rowKey="id"
922
+ selectData={setSelected}
923
+ pageSize={50}
924
+ itemsPerPage={[25, 50, 100]}
925
+ gridHeight={500}
926
+ />
927
+ );
928
+ }
929
+ ```
930
+
931
+ ### Example 2: Using accessorFn for Complex Data
932
+
933
+ ```jsx
934
+ function ConferenceGrid() {
935
+ const [selected, setSelected] = useState([]);
936
+
937
+ const columns = [
938
+ {
939
+ accessorKey: 'acronym',
940
+ accessorFn: (row) => row.acronym ?? '', // Handle null/undefined
941
+ header: 'Acronym',
942
+ type: 'textTitle'
943
+ },
944
+ {
945
+ accessorKey: 'fullName',
946
+ accessorFn: (row) => `${row.shortName || ''} - ${row.year || ''}`, // Combine fields
947
+ header: 'Conference Name',
948
+ type: 'text'
949
+ },
950
+ {
951
+ accessorKey: 'papers',
952
+ accessorFn: (row) => row.numberPapers?.value ?? 0, // Nested object with fallback
953
+ header: 'Papers',
954
+ type: 'integer'
955
+ },
956
+ {
957
+ accessorKey: 'averageRating',
958
+ accessorFn: (row) => row.ratings?.average ?? 0, // Nested with default
959
+ header: 'Avg Rating',
960
+ type: 'number'
961
+ },
962
+ {
963
+ accessorKey: 'status',
964
+ accessorFn: (row) => row.isActive ? 'Active' : 'Inactive', // Conditional
965
+ header: 'Status',
966
+ type: 'text'
967
+ },
968
+ {
969
+ accessorKey: 'organizers',
970
+ accessorFn: (row) => row.organizers?.map(o => o.name).join(', ') ?? 'N/A', // Array processing
971
+ header: 'Organizers',
972
+ type: 'text'
973
+ }
974
+ ];
975
+
976
+ const conferences = [
977
+ {
978
+ id: 1,
979
+ acronym: 'ICEIS',
980
+ shortName: 'International Conference on Enterprise Information Systems',
981
+ year: 2025,
982
+ numberPapers: { value: 150, trend: 'up' },
983
+ ratings: { average: 4.5, count: 200 },
984
+ isActive: true,
985
+ organizers: [{ name: 'John Doe' }, { name: 'Jane Smith' }]
986
+ },
987
+ {
988
+ id: 2,
989
+ acronym: null, // Will be handled by accessorFn
990
+ shortName: 'Conference on AI',
991
+ year: 2024,
992
+ numberPapers: null, // Will default to 0
993
+ ratings: { average: 3.8, count: 50 },
994
+ isActive: false,
995
+ organizers: []
996
+ }
997
+ ];
998
+
999
+ return (
1000
+ <DataGrid
1001
+ columns={columns}
1002
+ createRows={conferences}
1003
+ rowKey="id"
1004
+ selectData={setSelected}
1005
+ gridHeight={600}
1006
+ />
1007
+ );
1008
+ }
1009
+ ```
1010
+
1011
+ ### Example 3: Grid with Actions and Exports
1012
+
1013
+ ```jsx
1014
+ function ProductGrid() {
1015
+ const [selectedProducts, setSelectedProducts] = useState([]);
1016
+ const [products, setProducts] = useState(initialProducts);
1017
+
1018
+ const handleDelete = (rows) => {
1019
+ const ids = rows.map(r => r.productId);
1020
+ if (window.confirm(`Delete ${ids.length} product(s)?`)) {
1021
+ setProducts(prev => prev.filter(p => !ids.includes(p.productId)));
1022
+ }
1023
+ };
1024
+
1025
+ const handleEdit = (rows) => {
1026
+ if (rows.length === 1) {
1027
+ openEditModal(rows[0]);
1028
+ }
1029
+ };
1030
+
1031
+ const handleAddNew = () => {
1032
+ openCreateModal();
1033
+ };
1034
+
1035
+ const actions = [
1036
+ {
1037
+ name: 'Delete',
1038
+ function: handleDelete,
1039
+ tooltip: 'Delete selected products',
1040
+ color: 'red',
1041
+ icon: 'trash',
1042
+ selectionMode: 'multi',
1043
+ hasConfirmMessage: true,
1044
+ confirmMessage: 'Are you sure you want to delete the selected products?'
1045
+ },
1046
+ {
1047
+ name: 'Edit',
1048
+ function: handleEdit,
1049
+ tooltip: 'Edit product',
1050
+ color: 'blue',
1051
+ icon: 'edit',
1052
+ selectionMode: 'single'
1053
+ },
1054
+ {
1055
+ name: 'Add Product',
1056
+ function: handleAddNew,
1057
+ tooltip: 'Add new product',
1058
+ color: 'green',
1059
+ icon: 'plus',
1060
+ selectionMode: 'always'
1061
+ }
1062
+ ];
1063
+
1064
+ const columns = [
1065
+ { accessorKey: 'productId', header: 'ID', type: 'integer' },
1066
+ { accessorKey: 'name', header: 'Product Name', type: 'textTitle' },
1067
+ {
1068
+ accessorKey: 'price',
1069
+ accessorFn: (row) => row.price ?? 0, // Ensure numeric value
1070
+ header: 'Price',
1071
+ type: 'currency'
1072
+ },
1073
+ { accessorKey: 'stock', header: 'Stock', type: 'integer' },
1074
+ { accessorKey: 'category', header: 'Category', type: 'text' },
1075
+ ];
1076
+
1077
+ return (
1078
+ <DataGrid
1079
+ columns={columns}
1080
+ createRows={products}
1081
+ rowKey="productId"
1082
+ selectData={setSelectedProducts}
1083
+ actions={actions}
1084
+ hasExcelExport={true}
1085
+ hasPdfExport={true}
1086
+ gridHeight={600}
1087
+ />
1088
+ );
1089
+ }
1090
+ ```
1091
+
1092
+ ### Example 4: Hierarchical Data with SubRows
1093
+
1094
+ ```jsx
1095
+ function ProjectGrid() {
1096
+ const [selectedItems, setSelectedItems] = useState([]);
1097
+
1098
+ const columns = [
1099
+ { accessorKey: 'name', header: 'Name', type: 'textTitle' },
1100
+ { accessorKey: 'status', header: 'Status', type: 'text' },
1101
+ { accessorKey: 'assignee', header: 'Assignee', type: 'text' },
1102
+ { accessorKey: 'dueDate', header: 'Due Date', type: 'date', isDateColumn: true },
1103
+ ];
1104
+
1105
+ const data = [
1106
+ {
1107
+ id: 1,
1108
+ name: 'Project Alpha',
1109
+ status: 'Active',
1110
+ assignee: 'John Doe',
1111
+ dueDate: '2025-06-30',
1112
+ subRows: [
1113
+ { id: '1.1', name: 'Task 1: Design', status: 'Complete', assignee: 'Jane', dueDate: '2025-02-15' },
1114
+ { id: '1.2', name: 'Task 2: Development', status: 'In Progress', assignee: 'Bob', dueDate: '2025-04-30' },
1115
+ { id: '1.3', name: 'Task 3: Testing', status: 'Not Started', assignee: 'Alice', dueDate: '2025-06-15' }
1116
+ ]
1117
+ },
1118
+ {
1119
+ id: 2,
1120
+ name: 'Project Beta',
1121
+ status: 'Planning',
1122
+ assignee: 'Jane Smith',
1123
+ dueDate: '2025-12-31',
1124
+ subRows: [
1125
+ { id: '2.1', name: 'Task 1: Requirements', status: 'In Progress', assignee: 'John', dueDate: '2025-03-01' }
1126
+ ]
1127
+ }
1128
+ ];
1129
+
1130
+ return (
1131
+ <DataGrid
1132
+ columns={columns}
1133
+ createRows={data}
1134
+ rowKey="id"
1135
+ selectData={setSelectedItems}
1136
+ hasSubRows={true}
1137
+ enableExpanding={true}
1138
+ gridHeight={500}
1139
+ />
1140
+ );
1141
+ }
1142
+ ```
1143
+
1144
+ ### Example 5: Custom Styling and Virtualization
1145
+
1146
+ ```jsx
1147
+ function LargeDataGrid() {
1148
+ const [selectedRows, setSelectedRows] = useState([]);
1149
+
1150
+ // Custom cell with type support
1151
+ const StatusCell = ({ typeValue, cell, row }) => {
1152
+ const value = cell.getValue();
1153
+ const getColor = (status) => {
1154
+ switch (status) {
1155
+ case 'active': return 'green';
1156
+ case 'pending': return 'orange';
1157
+ case 'error': return 'red';
1158
+ default: return 'grey';
1159
+ }
1160
+ };
1161
+
1162
+ return (
1163
+ <span style={{
1164
+ color: getColor(value),
1165
+ fontWeight: 'bold',
1166
+ padding: '2px 8px',
1167
+ borderRadius: '4px',
1168
+ backgroundColor: `${getColor(value)}22`
1169
+ }}>
1170
+ {typeValue || value}
1171
+ </span>
1172
+ );
1173
+ };
1174
+
1175
+ const PriorityCell = ({ cell, row }) => {
1176
+ const priority = cell.getValue();
1177
+ const icons = {
1178
+ high: '🔴',
1179
+ medium: '🟡',
1180
+ low: '🟢'
1181
+ };
1182
+
1183
+ return (
1184
+ <span>
1185
+ {icons[priority]} {priority.toUpperCase()}
1186
+ </span>
1187
+ );
1188
+ };
1189
+
1190
+ const getRowStyle = ({ row }) => {
1191
+ const styles = {};
1192
+
1193
+ if (row.original.status === 'error') {
1194
+ styles.backgroundColor = '#ffebee';
1195
+ }
1196
+
1197
+ if (row.original.priority === 'high') {
1198
+ styles.borderLeft = '3px solid red';
1199
+ }
1200
+
1201
+ if (row.original.isArchived) {
1202
+ styles.opacity = 0.5;
1203
+ }
1204
+
1205
+ return styles;
1206
+ };
1207
+
1208
+ const columns = [
1209
+ { accessorKey: 'id', header: 'ID', type: 'integer' },
1210
+ {
1211
+ accessorKey: 'status',
1212
+ header: 'Status',
1213
+ type: 'text',
1214
+ Cell: StatusCell
1215
+ },
1216
+ {
1217
+ accessorKey: 'priority',
1218
+ header: 'Priority',
1219
+ Cell: PriorityCell
1220
+ },
1221
+ { accessorKey: 'name', header: 'Name', type: 'text' },
1222
+ {
1223
+ accessorKey: 'value',
1224
+ accessorFn: (row) => row.value ?? 0, // Ensure numeric value for currency
1225
+ header: 'Value',
1226
+ type: 'currency'
1227
+ },
1228
+ {
1229
+ accessorKey: 'progress',
1230
+ accessorFn: (row) => row.progress ?? 0, // Ensure numeric value for percentage
1231
+ header: 'Progress',
1232
+ type: 'percentage'
1233
+ },
1234
+ { accessorKey: 'updatedAt', header: 'Updated', type: 'datetime', isDateColumn: true },
1235
+ ];
1236
+
1237
+ // Generate large dataset
1238
+ const largeDataset = Array.from({ length: 5000 }, (_, i) => ({
1239
+ id: i + 1,
1240
+ status: ['active', 'pending', 'error'][i % 3],
1241
+ priority: ['high', 'medium', 'low'][i % 3],
1242
+ name: `Item ${i + 1}`,
1243
+ value: Math.random() * 10000,
1244
+ progress: Math.random(),
1245
+ updatedAt: new Date(Date.now() - Math.random() * 365 * 24 * 60 * 60 * 1000).toISOString(),
1246
+ isArchived: i % 10 === 0
1247
+ }));
1248
+
1249
+ return (
1250
+ <DataGrid
1251
+ columns={columns}
1252
+ createRows={largeDataset}
1253
+ rowKey="id"
1254
+ selectData={setSelectedRows}
1255
+ enableVirtualization={true}
1256
+ enableCompactStyleMode={true}
1257
+ rowHeight={40}
1258
+ fontSize={12}
1259
+ gridHeight="calc(100vh - 200px)"
1260
+ getRowStyle={getRowStyle}
1261
+ pageSize={100}
1262
+ itemsPerPage={[50, 100, 200, 500]}
1263
+ />
1264
+ );
1265
+ }
1266
+ ```
1267
+
1268
+ ### Example 6: Advanced Features with Cache Management
1269
+
1270
+ ```jsx
1271
+ function AdvancedGrid() {
1272
+ const [data, setData] = useState([]);
1273
+ const [cacheLoading, setCacheLoading] = useState(false);
1274
+ const [selectedRows, setSelectedRows] = useState([]);
1275
+ const [visibleRowCount, setVisibleRowCount] = useState(0);
1276
+
1277
+ const refreshData = async () => {
1278
+ setCacheLoading(true);
1279
+ try {
1280
+ const newData = await fetchLatestData();
1281
+ setData(newData);
1282
+ } catch (error) {
1283
+ console.error('Failed to refresh data:', error);
1284
+ } finally {
1285
+ setCacheLoading(false);
1286
+ }
1287
+ };
1288
+
1289
+ const handleVisibleRowsChange = (rows) => {
1290
+ setVisibleRowCount(rows.length);
1291
+ console.log('Visible rows:', rows);
1292
+ };
1293
+
1294
+ const exportCustom = () => {
1295
+ console.log('Custom export logic');
1296
+ };
1297
+
1298
+ const actions = [
1299
+ {
1300
+ name: 'Process',
1301
+ function: (rows) => processSelectedRows(rows),
1302
+ tooltip: 'Process selected items',
1303
+ color: 'blue',
1304
+ icon: 'cog',
1305
+ selectionMode: 'multi'
1306
+ }
1307
+ ];
1308
+
1309
+ const extraActions = [
1310
+ {
1311
+ function: exportCustom,
1312
+ content: 'Custom Export',
1313
+ tooltip: 'Export with custom format',
1314
+ icon: 'file alternate outline'
1315
+ }
1316
+ ];
1317
+
1318
+ const columns = [
1319
+ { accessorKey: 'id', header: 'ID', type: 'integer' },
1320
+ { accessorKey: 'name', header: 'Name', type: 'textTitle' },
1321
+ { accessorKey: 'status', header: 'Status', type: 'text' },
1322
+ {
1323
+ accessorKey: 'amount',
1324
+ accessorFn: (row) => row.amount ?? 0, // Ensure numeric value
1325
+ header: 'Amount',
1326
+ type: 'currency'
1327
+ },
1328
+ { accessorKey: 'createdAt', header: 'Created', type: 'datetime', isDateColumn: true },
1329
+ ];
1330
+
1331
+ return (
1332
+ <DataGrid
1333
+ columns={columns}
1334
+ createRows={data}
1335
+ rowKey="id"
1336
+ selectData={setSelectedRows}
1337
+
1338
+ // Actions
1339
+ actions={actions}
1340
+ extraActions={extraActions}
1341
+
1342
+ // Advanced features
1343
+ enableGlobalFilter={true}
1344
+ globalFilterFn="fuzzy"
1345
+ enableColumnFilterModes={true}
1346
+ enableFixedHeader={true}
1347
+ enableFixedActions={true}
1348
+
1349
+ // Cache management
1350
+ updateCache={refreshData}
1351
+ cacheUpdateText="Refresh data from server"
1352
+ cacheUpdating={cacheLoading}
1353
+
1354
+ // Callbacks
1355
+ onVisibleRowsChange={handleVisibleRowsChange}
1356
+
1357
+ // Exports
1358
+ hasExcelExport={true}
1359
+ hasPdfExport={true}
1360
+
1361
+ // Help
1362
+ gridHelper={{
1363
+ title: 'Data Grid Help',
1364
+ content: (
1365
+ <div>
1366
+ <h3>Quick Guide</h3>
1367
+ <ul>
1368
+ <li><strong>Selection:</strong> Click rows to select, use checkboxes for multi-select</li>
1369
+ <li><strong>Filtering:</strong> Use column filters to search specific fields</li>
1370
+ <li><strong>Global Search:</strong> Search across all columns at once</li>
1371
+ <li><strong>Sorting:</strong> Click column headers to sort</li>
1372
+ <li><strong>Export:</strong> Use Excel or PDF buttons to export data</li>
1373
+ <li><strong>Refresh:</strong> Click cache button to reload latest data</li>
1374
+ </ul>
1375
+ <p><strong>Currently showing:</strong> {visibleRowCount} rows</p>
1376
+ </div>
1377
+ )
1378
+ }}
1379
+
1380
+ // Display
1381
+ gridHeight={700}
1382
+ pageSize={100}
1383
+ itemsPerPage={[50, 100, 200]}
1384
+ />
1385
+ );
1386
+ }
1387
+ ```
1388
+
1389
+ ### Example 7: Disabled Rows and Custom Row Styles
1390
+
1391
+ ```jsx
1392
+ function OrderGrid() {
1393
+ const [orders, setOrders] = useState([]);
1394
+ const [selected, setSelected] = useState([]);
1395
+
1396
+ // Disable completed and cancelled orders from selection
1397
+ const getDisabledRows = () => {
1398
+ return orders
1399
+ .filter(order => ['completed', 'cancelled'].includes(order.status))
1400
+ .map(order => order.orderId);
1401
+ };
1402
+
1403
+ const getRowStyle = ({ row }) => {
1404
+ const status = row.original.status;
1405
+
1406
+ switch (status) {
1407
+ case 'pending':
1408
+ return { backgroundColor: '#fff3cd' };
1409
+ case 'processing':
1410
+ return { backgroundColor: '#cfe2ff' };
1411
+ case 'completed':
1412
+ return { backgroundColor: '#d1e7dd', opacity: 0.7 };
1413
+ case 'cancelled':
1414
+ return { backgroundColor: '#f8d7da', opacity: 0.7 };
1415
+ default:
1416
+ return {};
1417
+ }
1418
+ };
1419
+
1420
+ const columns = [
1421
+ { accessorKey: 'orderId', header: 'Order ID', type: 'text' },
1422
+ { accessorKey: 'customer', header: 'Customer', type: 'textTitle' },
1423
+ {
1424
+ accessorKey: 'total',
1425
+ accessorFn: (row) => row.total ?? 0, // Ensure numeric value
1426
+ header: 'Total',
1427
+ type: 'currency'
1428
+ },
1429
+ { accessorKey: 'status', header: 'Status', type: 'text' },
1430
+ { accessorKey: 'orderDate', header: 'Order Date', type: 'datetime', isDateColumn: true },
1431
+ ];
1432
+
1433
+ return (
1434
+ <DataGrid
1435
+ columns={columns}
1436
+ createRows={orders}
1437
+ rowKey="orderId"
1438
+ selectData={setSelected}
1439
+ disableRows={getDisabledRows()}
1440
+ getRowStyle={getRowStyle}
1441
+ gridHeight={600}
1442
+ />
1443
+ );
1444
+ }
1445
+ ```
1446
+
1447
+ ---
1448
+
1449
+ ## API Reference
1450
+
1451
+ ### Column Definition Object
1452
+
1453
+ ```typescript
1454
+ interface ColumnDefinition {
1455
+ // Required
1456
+ accessorKey: string; // Key identifier for the column
1457
+ header: string; // Column header text
1458
+
1459
+ // Data Access (choose one)
1460
+ // Option 1: Direct property access (default when no accessorFn)
1461
+ // Option 2: Custom accessor function
1462
+ accessorFn?: (row: Object) => any; // Function to extract/compute value from row
1463
+
1464
+ // Type & Rendering
1465
+ type?: string; // Cell type for automatic formatting
1466
+ Cell?: React.Component; // Custom cell renderer (receives typeValue)
1467
+ cellClass?: string; // CSS class wrapper for cell content
1468
+
1469
+ // Filtering
1470
+ enableColumnFilter?: boolean; // Default: true
1471
+ enableColumnFilterModes?: boolean;// Default: true
1472
+ filterFn?: string | function; // Default: 'contains' (or undefined for dates)
1473
+
1474
+ // Sorting
1475
+ enableSorting?: boolean; // Default: true
1476
+ sortingFn?: string | function; // Default: 'basic' (or custom for dates)
1477
+ isDateColumn?: boolean; // Special date handling (default: false)
1478
+
1479
+ // Display
1480
+ enableResizing?: boolean; // Default: true
1481
+ grow?: boolean; // Column can grow (default: true)
1482
+ enableClickToCopy?: boolean; // Default: false
1483
+ enableColumnActions?: boolean; // Default: false
1484
+
1485
+ // Additional
1486
+ locale?: string; // Locale for formatting (e.g., 'en-US')
1487
+ onlyFlag?: boolean; // For countryFlag type
1488
+ columnDef?: object; // Additional metadata
1489
+ }
1490
+ ```
1491
+
1492
+ ### Action Object
1493
+
1494
+ ```typescript
1495
+ interface ActionObject {
1496
+ // Required
1497
+ name: string; // Button label
1498
+ function: (selectedRows: Array, table?: Object) => void; // Click handler
1499
+
1500
+ // Display
1501
+ tooltip?: string; // Hover tooltip
1502
+ color?: 'blue' | 'red' | 'green' | 'yellow' | 'orange' | 'black' | 'grey' |
1503
+ 'teal' | 'brown' | 'violet' | 'purple' | 'olive' | 'pink';
1504
+ icon?: string | React.Element; // Icon name or element
1505
+
1506
+ // Behavior
1507
+ selectionMode?: 'single' | 'multi' | 'always';
1508
+ confirmMessage?: string | React.Element;
1509
+ hasConfirmMessage?: boolean;
1510
+ disabled?: boolean;
1511
+ visible?: boolean; // Default: true
1512
+
1513
+ // Toggle mode
1514
+ toggle?: boolean;
1515
+ active?: boolean;
1516
+
1517
+ // Other
1518
+ key?: string; // Unique React key
1519
+ }
1520
+ ```
1521
+
1522
+ ### Extra Action Object
1523
+
1524
+ ```typescript
1525
+ interface ExtraActionObject {
1526
+ // Required
1527
+ function: () => void; // Click handler
1528
+ content: string | React.Element; // Button content/label
1529
+
1530
+ // Display
1531
+ tooltip?: string; // Hover tooltip
1532
+ icon?: string | React.Element; // Icon name or element
1533
+ style?: React.CSSProperties; // Custom button styles
1534
+ propsButton?: object; // Additional Semantic UI Button props
1535
+ }
1536
+ ```
1537
+
1538
+ ### Data Row Object
1539
+
1540
+ ```typescript
1541
+ interface DataRow {
1542
+ [rowKey: string]: any; // Unique identifier (required)
1543
+ [key: string]: any; // Other data fields
1544
+
1545
+ // Optional: For hierarchical data
1546
+ subRows?: Array<DataRow>;
1547
+ isSubRow?: boolean;
1548
+ }
1549
+ ```
1550
+
1551
+ ---
1552
+
1553
+ ## Performance Tips
1554
+
1555
+ ### 1. Use Virtualization for Large Datasets
1556
+ ```jsx
1557
+ // For 1000+ rows
1558
+ enableVirtualization={true}
1559
+ ```
1560
+
1561
+ ### 2. Optimize Row Height and Compact Mode
1562
+ ```jsx
1563
+ // Smaller rows = more visible data
1564
+ rowHeight={40}
1565
+ enableCompactStyleMode={true}
1566
+ fontSize={12}
1567
+ ```
1568
+
1569
+ ### 3. Disable Unused Features
1570
+ ```jsx
1571
+ // Reduce overhead by disabling features you don't need
1572
+ enableDensityToggle={false}
1573
+ enableFullScreenToggle={false}
1574
+ enableGlobalFilter={false}
1575
+ enableColumnFilterModes={false}
1576
+ ```
1577
+
1578
+ ### 4. Limit Initial Page Size
1579
+ ```jsx
1580
+ // Don't render too many rows initially
1581
+ pageSize={50} // Instead of 150
1582
+ itemsPerPage={[25, 50, 100]}
1583
+ ```
1584
+
1585
+ ### 5. Pre-select Rows Carefully
1586
+ ```jsx
1587
+ // Only include necessary IDs
1588
+ selectedIds={criticalIds} // Instead of selecting all rows
1589
+ ```
1590
+
1591
+ ### 6. Optimize Custom Cell Renderers
1592
+ ```jsx
1593
+ // Use typeValue when available
1594
+ const MyCell = ({ typeValue, cell }) => {
1595
+ return typeValue || cell.getValue(); // Prefer pre-formatted typeValue
1596
+ };
1597
+
1598
+ // Memoize expensive computations
1599
+ const ExpensiveCell = React.memo(({ cell }) => {
1600
+ const processedValue = useMemo(() => expensiveComputation(cell.getValue()), [cell]);
1601
+ return <div>{processedValue}</div>;
1602
+ });
1603
+ ```
1604
+
1605
+ ### 7. Keep accessorFn Lightweight
1606
+ ```jsx
1607
+ // Bad - Complex computation on every render/filter/sort
1608
+ accessorFn: (row) => {
1609
+ return expensiveCalculation(row.data);
1610
+ }
1611
+
1612
+ // Good - Simple, fast operations
1613
+ accessorFn: (row) => row.data?.value ?? 0
1614
+
1615
+ // Better - Pre-process data before passing to grid
1616
+ const processedData = rawData.map(row => ({
1617
+ ...row,
1618
+ computedValue: expensiveCalculation(row.data)
1619
+ }));
1620
+ ```
1621
+
1622
+ ### 8. Use Column Visibility Wisely
1623
+ ```jsx
1624
+ // Hide columns that aren't immediately needed
1625
+ columnVisibilityState={{
1626
+ metadata: false,
1627
+ internalId: false,
1628
+ debugInfo: false
1629
+ }}
1630
+ ```
1631
+
1632
+ ### 9. Implement Efficient Row Styling
1633
+ ```jsx
1634
+ // Keep getRowStyle lightweight
1635
+ getRowStyle={({ row }) => {
1636
+ // Simple conditional - avoid heavy computation
1637
+ return row.original.isHighlighted ? { backgroundColor: '#fffacd' } : {};
1638
+ }}
1639
+ ```
1640
+
1641
+ ### 10. Batch State Updates
1642
+ ```jsx
1643
+ // Instead of multiple state updates, batch them
1644
+ const handleMultipleChanges = () => {
1645
+ // Use a single state update with derived values
1646
+ setData(prevData => processAndUpdate(prevData));
1647
+ };
1648
+ ```
1649
+
1650
+ ### 11. Leverage React's Built-in Optimizations
1651
+ ```jsx
1652
+ // Use keys properly for subRows
1653
+ const data = subRowData.map((item, index) => ({
1654
+ ...item,
1655
+ id: `${parentId}.${index}` // Stable, unique keys
1656
+ }));
1657
+ ```
1658
+
1659
+ ---
1660
+
1661
+ ## Browser Support
1662
+
1663
+ - **Chrome:** Latest version (recommended)
1664
+ - **Firefox:** Latest version
1665
+ - **Safari:** Latest version
1666
+ - **Edge:** Latest version (Chromium-based)
1667
+
1668
+ ### CSS Requirements
1669
+ - CSS Grid support (all modern browsers)
1670
+ - CSS Sticky positioning for fixed headers
1671
+ - Flexbox for layouts
1672
+
1673
+ ---
1674
+
1675
+ ## Troubleshooting
1676
+
1677
+ ### Common Issues
1678
+
1679
+ #### **Issue: Rows not selecting when clicked**
1680
+
1681
+ **Symptoms:** Clicking rows doesn't select them, checkboxes don't appear
1682
+
1683
+ **Solutions:**
1684
+ - Verify `disableSelect={false}` (this is the default)
1685
+ - Ensure `selectData` callback is provided
1686
+ - Check that `rowKey` matches your data's unique identifier property
1687
+ - Verify rows aren't in the `disableRows` array
1688
+
1689
+ ```jsx
1690
+ // Correct configuration
1691
+ <DataGrid
1692
+ rowKey="id" // Matches data[0].id
1693
+ selectData={handleSelection} // Required callback
1694
+ disableSelect={false} // Optional - default is false
1695
+ disableRows={[]} // No disabled rows
1696
+ />
1697
+ ```
1698
+
1699
+ #### **Issue: Date columns not sorting correctly**
1700
+
1701
+ **Symptoms:** Dates sort alphabetically instead of chronologically
1702
+
1703
+ **Solutions:**
1704
+ - Set `isDateColumn={true}` on date columns
1705
+ - Ensure date values are in valid ISO 8601 format (`YYYY-MM-DD` or `YYYY-MM-DDTHH:mm:ss`)
1706
+ - Check that date strings are parseable by JavaScript `Date` constructor
1707
+
1708
+ ```jsx
1709
+ // Correct date column configuration
1710
+ {
1711
+ accessorKey: 'createdAt',
1712
+ header: 'Created Date',
1713
+ type: 'date',
1714
+ isDateColumn: true // Enables date-aware sorting
1715
+ }
1716
+
1717
+ // Data format
1718
+ const data = [
1719
+ { id: 1, createdAt: '2025-01-15' }, // ISO 8601 format
1720
+ { id: 2, createdAt: '2024-12-20' },
1721
+ ];
1722
+ ```
1723
+
1724
+ #### **Issue: Fixed headers not working**
1725
+
1726
+ **Symptoms:** Headers scroll with content instead of staying fixed
1727
+
1728
+ **Solutions:**
1729
+ - Set `enableFixedHeader={true}` (default is true)
1730
+ - Ensure `gridHeight` is set to a specific numeric value or CSS string
1731
+ - Do not use `gridHeight="fit-content"` with fixed headers
1732
+ - Check for CSS conflicts with `grid-sticky-header` class
1733
+
1734
+ ```jsx
1735
+ // Correct fixed header configuration
1736
+ <DataGrid
1737
+ enableFixedHeader={true}
1738
+ gridHeight={600} // Or "80vh", not "fit-content"
1739
+ />
1740
+ ```
1741
+
1742
+ #### **Issue: Fixed actions toolbar not sticking**
1743
+
1744
+ **Symptoms:** Action buttons scroll instead of staying at top
1745
+
1746
+ **Solutions:**
1747
+ - Enable both `enableFixedHeader={true}` and `enableFixedActions={true}`
1748
+ - Verify `gridHeight` is set to a specific value
1749
+ - Check for CSS conflicts with `grid-sticky-actions` class
1750
+
1751
+ ```jsx
1752
+ <DataGrid
1753
+ enableFixedHeader={true}
1754
+ enableFixedActions={true}
1755
+ gridHeight={700}
1756
+ />
1757
+ ```
1758
+
1759
+ #### **Issue: Selection state not syncing with parent component**
1760
+
1761
+ **Symptoms:** External state doesn't match grid selection
1762
+
1763
+ **Solutions:**
1764
+ - Use the `selectedIds` prop to control selection from parent
1765
+ - Component automatically syncs when `selectedIds` prop changes
1766
+ - Ensure `rowKey` values in `selectedIds` match data
1767
+
1768
+ ```jsx
1769
+ const [externalSelection, setExternalSelection] = useState([1, 5, 10]);
1770
+
1771
+ <DataGrid
1772
+ selectedIds={externalSelection} // Controlled selection
1773
+ selectData={(rows) => {
1774
+ const ids = rows.map(r => r.id);
1775
+ setExternalSelection(ids);
1776
+ }}
1777
+ />
1778
+ ```
1779
+
1780
+ #### **Issue: Export buttons not appearing**
1781
+
1782
+ **Symptoms:** Excel/PDF export buttons are not visible
1783
+
1784
+ **Solutions:**
1785
+ - Set `hasExcelExport={true}` and/or `hasPdfExport={true}`
1786
+ - Check that `disableSideActions={false}` (default)
1787
+ - Ensure toolbar has space (not too many actions)
1788
+ - Verify `enableTopToolbar={true}` (default)
1789
+
1790
+ ```jsx
1791
+ <DataGrid
1792
+ hasExcelExport={true}
1793
+ hasPdfExport={true}
1794
+ enableTopToolbar={true}
1795
+ disableSideActions={false}
1796
+ />
1797
+ ```
1798
+
1799
+ #### **Issue: Type formatter not working**
1800
+
1801
+ **Symptoms:** Column values appear as raw data instead of formatted
1802
+
1803
+ **Solutions:**
1804
+ - Verify column has `type` property defined
1805
+ - Check that `type` value exists in `DEFAULT_CELL_TYPES` (e.g., 'text', 'date', 'currency', 'email')
1806
+ - Ensure data values are in correct format for the type
1807
+ - Check browser console for errors
1808
+
1809
+ ```jsx
1810
+ // Correct type configuration
1811
+ {
1812
+ accessorKey: 'price',
1813
+ header: 'Price',
1814
+ type: 'currency' // Must match a valid type
1815
+ }
1816
+ ```
1817
+
1818
+ #### **Issue: Custom Cell component not receiving typeValue**
1819
+
1820
+ **Symptoms:** `typeValue` prop is undefined in custom Cell
1821
+
1822
+ **Solutions:**
1823
+ - Verify column has both `type` AND `Cell` defined
1824
+ - Check that `type` matches a key in `DEFAULT_CELL_TYPES`
1825
+ - `typeValue` only exists when type formatter is applied
1826
+
1827
+ ```jsx
1828
+ // Correct configuration for typeValue
1829
+ const CustomCell = ({ typeValue, cell }) => {
1830
+ console.log(typeValue); // Will be defined
1831
+ return <div>{typeValue}</div>;
1832
+ };
1833
+
1834
+ {
1835
+ accessorKey: 'amount',
1836
+ type: 'currency', // Required for typeValue
1837
+ Cell: CustomCell // Will receive typeValue
1838
+ }
1839
+ ```
1840
+
1841
+ #### **Issue: accessorFn not being used for filtering/sorting**
1842
+
1843
+ **Symptoms:** Filters and sorts use raw data instead of accessorFn result
1844
+
1845
+ **Solutions:**
1846
+ - Verify `accessorFn` is defined correctly
1847
+ - The returned value from `accessorFn` is what gets filtered/sorted
1848
+ - For complex objects, ensure `accessorFn` returns a simple value
1849
+
1850
+ ```jsx
1851
+ // Bad - Returns object (hard to filter/sort)
1852
+ accessorFn: (row) => ({ value: row.data })
1853
+
1854
+ // Good - Returns simple value
1855
+ accessorFn: (row) => row.data?.value ?? 0
1856
+ ```
1857
+
1858
+ #### **Issue: Virtualization causing scroll issues**
1859
+
1860
+ **Symptoms:** Jerky scrolling, rows not rendering, blank spaces
1861
+
1862
+ **Solutions:**
1863
+ - Ensure `rowHeight` is set accurately
1864
+ - Don't use dynamic row heights with virtualization
1865
+ - Check that `enableVirtualization={true}` is actually needed (only for 1000+ rows)
1866
+ - Verify data doesn't change reference on every render
1867
+
1868
+ ```jsx
1869
+ // Good for virtualization
1870
+ <DataGrid
1871
+ enableVirtualization={true}
1872
+ rowHeight={40} // Fixed height
1873
+ createRows={stableDataReference} // Don't recreate array
1874
+ />
1875
+ ```
1876
+
1877
+ #### **Issue: Actions not enabling/disabling correctly**
1878
+
1879
+ **Symptoms:** Action buttons stay disabled when rows are selected
1880
+
1881
+ **Solutions:**
1882
+ - Check `selectionMode` setting ('single', 'multi', 'always')
1883
+ - Verify `disabled` prop isn't set to true
1884
+ - Ensure rows are actually being selected (check `selectData` callback)
1885
+
1886
+ ```jsx
1887
+ actions={[
1888
+ {
1889
+ name: 'Edit',
1890
+ selectionMode: 'single', // Requires exactly 1 row
1891
+ function: handleEdit,
1892
+ disabled: false // Not manually disabled
1893
+ }
1894
+ ]}
1895
+ ```
1896
+
1897
+ #### **Issue: Hierarchical data (subRows) not working**
1898
+
1899
+ **Symptoms:** SubRows don't expand or aren't selectable
1900
+
1901
+ **Solutions:**
1902
+ - Set `hasSubRows={true}`
1903
+ - Set `enableExpanding={true}` to show expand icons
1904
+ - Ensure data has correct `subRows` structure
1905
+ - SubRow IDs should follow pattern: `"parentId.index"`
1906
+ ```jsx
1907
+ const hierarchicalData = [
1908
+ {
1909
+ id: 1,
1910
+ name: 'Parent',
1911
+ subRows: [
1912
+ { id: '1.1', name: 'Child 1' },
1913
+ { id: '1.2', name: 'Child 2' }
1914
+ ]
1915
+ }
1916
+ ];
1917
+
1918
+ <DataGrid
1919
+ hasSubRows={true}
1920
+ enableExpanding={true}
1921
+ createRows={hierarchicalData}
1922
+ />
1923
+ ```
1924
+
1925
+ #### **Issue: Cache update button not appearing**
1926
+
1927
+ **Symptoms:** Cache/refresh button is not visible
1928
+
1929
+ **Solutions:**
1930
+ - Provide `updateCache` function prop
1931
+ - Optionally set `cacheUpdateText` for tooltip
1932
+ - Button only appears when `updateCache` is defined
1933
+
1934
+ ```jsx
1935
+ <DataGrid
1936
+ updateCache={() => fetchLatestData()}
1937
+ cacheUpdateText="Refresh from server"
1938
+ cacheUpdating={isLoading}
1939
+ />
1940
+ ```
1941
+
1942
+ #### **Issue: Row styles not applying**
1943
+
1944
+ **Symptoms:** `getRowStyle` returns styles but they don't appear
1945
+
1946
+ **Solutions:**
1947
+ - Check that returned object contains valid CSS properties
1948
+ - Verify function is actually being called
1949
+ - CSS specificity might be overriding - use `!important` if needed
1950
+ - Check browser console for CSS errors
1951
+
1952
+ ```jsx
1953
+ getRowStyle={({ row }) => {
1954
+ console.log('Styling row:', row.id); // Debug
1955
+ return {
1956
+ backgroundColor: row.original.isHighlighted ? '#fffacd !important' : 'white'
1957
+ };
1958
+ }}
1959
+ ```
1960
+
1961
+ #### **Issue: Filters not working**
1962
+
1963
+ **Symptoms:** Column filters don't filter data
1964
+
1965
+ **Solutions:**
1966
+ - Verify `enableColumnFilter={true}` on columns (default)
1967
+ - Check that `filterFn` is valid
1968
+ - Ensure data values match filter input type
1969
+ - If using `accessorFn`, ensure it returns filterable values
1970
+
1971
+ ```jsx
1972
+ {
1973
+ accessorKey: 'status',
1974
+ header: 'Status',
1975
+ enableColumnFilter: true,
1976
+ filterFn: 'contains' // or 'equals', 'startsWith', etc.
1977
+ }
1978
+
1979
+ // With accessorFn
1980
+ {
1981
+ accessorKey: 'papers',
1982
+ accessorFn: (row) => row.numberPapers?.value ?? 0, // Returns number for filtering
1983
+ header: 'Papers',
1984
+ type: 'integer'
1985
+ }
1986
+ ```
1987
+
1988
+ ---
1989
+
1990
+
1991
+ ## Important Notes
1992
+
1993
+ ### Row Selection Behavior
1994
+ - **Disabled Select:** When `disableSelect={true}` hide the selection checkbox/radio and cannot be selected
1995
+ - **Single selection mode:** When `enableMultiRowSelection={false}`, clicking a row deselects all others
1996
+ - **Multi-selection:** Use checkboxes when `enableMultiRowSelection={true}`
1997
+ - **Selection state:** Controlled via `rowSelection` state and `selectData` callback
1998
+
1999
+ ### Fixed Header and Actions
2000
+ - `enableFixedHeader` uses CSS `position: sticky` on column headers
2001
+ - `enableFixedActions` (requires `enableFixedHeader={true}`) also pins the toolbar
2002
+ - Both require `gridHeight` to be set to a specific value (not 'fit-content')
2003
+ - CSS classes: `grid-sticky-header` and `grid-sticky-actions`
2004
+
2005
+ ### Date Columns
2006
+ - Use `type: 'date'` for date-only display (no time)
2007
+ - Use `type: 'datetime'` for full datetime display
2008
+ - Default locale is 'pt-PT' - override with `locale` prop on column
2009
+ - Date values should be ISO 8601 format for best results
2010
+
2011
+ ### accessorFn Performance
2012
+ - `accessorFn` is called for **every cell render, filter operation, and sort operation**
2013
+ - Keep computations lightweight
2014
+ - Avoid creating new objects/arrays in `accessorFn`
2015
+ - Pre-process complex data before passing to the grid when possible
2016
+ - The returned value is what gets filtered and sorted
2017
+
2018
+ ### LocalizationProvider
2019
+ - Component is wrapped with MUI's `LocalizationProvider` using `AdapterDateFns`
2020
+ - Required for date picker functionality in filters
2021
+ - No need to add this provider in your own code
2022
+
2023
+ ### SubRows and Hierarchical Data
2024
+ - SubRow IDs follow pattern: `"parentId.subRowIndex"` (e.g., "1.0", "1.1")
2025
+ - Selection works on both parent and child rows
2026
+ - Visual depth indicated by background color and padding
2027
+ - Requires `hasSubRows={true}` to enable
2028
+
2029
+ ### Performance Considerations
2030
+ - Virtualization is recommended for 1000+ rows
2031
+ - Compact style mode reduces render overhead
2032
+ - Custom cell components should be memoized when possible
2033
+ - Avoid recreating data arrays on every render
2034
+ - Keep `accessorFn` computations lightweight
2035
+
2036
+ ### Browser Storage
2037
+ - Component does NOT use localStorage or sessionStorage
2038
+ - All state is maintained in React state (useState)
2039
+ - Selection state is ephemeral unless managed by parent
2040
+
2041
+ ---
2042
+
2043
+
2044
+ ## Dependencies
2045
+
2046
+ This component requires the following peer dependencies:
2047
+
2048
+ ### Core Dependencies
2049
+ - **react** (^16.8.0 || ^17.0.0 || ^18.0.0) - React framework
2050
+ - **prop-types** - Runtime type checking for React props
2051
+ - **material-react-table** - Core table functionality and hooks
2052
+ - **@mui/material** - Material UI components
2053
+ - **@mui/x-date-pickers** - Date picker components for filters
2054
+ - **date-fns** - Date manipulation and formatting
2055
+ - **semantic-ui-react** - Semantic UI React components for buttons and icons
2056
+ - **bootstrap** - Base CSS framework
2057
+ - **semantic-ui-css** - Semantic UI CSS styles
2058
+
2059
+ ### Version Compatibility
2060
+ ```json
2061
+ {
2062
+ "peerDependencies": {
2063
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0",
2064
+ "material-react-table": "^2.0.0",
2065
+ "@mui/material": "^5.0.0",
2066
+ "semantic-ui-react": "^2.0.0"
2067
+ }
2068
+ }
2069
+ ```
2070
+
2071
+ ### Built With
2072
+ - [Material React Table](https://www.material-react-table.com/) - Advanced table features
2073
+ - [MUI (Material-UI)](https://mui.com/) - UI components and theming
2074
+ - [Semantic UI React](https://react.semantic-ui.com/) - Button and icon components
2075
+ - [Bootstrap](https://getbootstrap.com/) - CSS utilities
2076
+ - [date-fns](https://date-fns.org/) - Modern JavaScript date utility library
2077
+
2078
+ ---
2079
+
2080
+ ## License
2081
+
2082
+ ISC
2083
+
2084
+ ---