0
# Selection and Events
1
2
Comprehensive selection system supporting single cells, multiple rows, and range selection with keyboard shortcuts and event handling.
3
4
## Capabilities
5
6
### Row Selection
7
8
Multi-row selection system with various selection methods and interaction patterns.
9
10
```javascript { .api }
11
interface RowSelection {
12
/** Enable shift-click for multi-row selection */
13
enableShiftSelect?: boolean;
14
/** Called when rows are selected */
15
onRowsSelected?: (rows: SelectedRow[]) => void;
16
/** Called when rows are deselected */
17
onRowsDeselected?: (rows: SelectedRow[]) => void;
18
/** Show checkbox column for row selection */
19
showCheckbox?: boolean;
20
/** Method for determining which rows are selected */
21
selectBy: SelectionMethod;
22
}
23
24
type SelectionMethod =
25
| { indexes: number[] }
26
| { isSelectedKey: string }
27
| { keys: { values: any[]; rowKey: string } };
28
29
interface SelectedRow {
30
rowIdx: number;
31
row: any;
32
}
33
```
34
35
**Row Selection Examples:**
36
37
```javascript
38
import ReactDataGrid from 'react-data-grid';
39
40
// Selection by indexes
41
const IndexBasedSelection = () => {
42
const [selectedIndexes, setSelectedIndexes] = useState([]);
43
44
const rowSelection = {
45
showCheckbox: true,
46
enableShiftSelect: true,
47
onRowsSelected: (rows) => {
48
const newIndexes = [...selectedIndexes, ...rows.map(r => r.rowIdx)];
49
setSelectedIndexes(newIndexes);
50
},
51
onRowsDeselected: (rows) => {
52
const deselectedIndexes = rows.map(r => r.rowIdx);
53
setSelectedIndexes(selectedIndexes.filter(i => !deselectedIndexes.includes(i)));
54
},
55
selectBy: {
56
indexes: selectedIndexes
57
}
58
};
59
60
return (
61
<ReactDataGrid
62
columns={columns}
63
rowGetter={i => rows[i]}
64
rowsCount={rows.length}
65
minHeight={400}
66
rowSelection={rowSelection}
67
/>
68
);
69
};
70
71
// Selection by row property
72
const PropertyBasedSelection = () => {
73
const [rows, setRows] = useState(initialRows);
74
75
const rowSelection = {
76
showCheckbox: true,
77
onRowsSelected: (selectedRows) => {
78
const updatedRows = rows.map(row => {
79
const isSelected = selectedRows.some(sr => sr.row.id === row.id);
80
return { ...row, isSelected };
81
});
82
setRows(updatedRows);
83
},
84
onRowsDeselected: (deselectedRows) => {
85
const updatedRows = rows.map(row => {
86
const isDeselected = deselectedRows.some(dr => dr.row.id === row.id);
87
return isDeselected ? { ...row, isSelected: false } : row;
88
});
89
setRows(updatedRows);
90
},
91
selectBy: {
92
isSelectedKey: 'isSelected'
93
}
94
};
95
96
return (
97
<ReactDataGrid
98
columns={columns}
99
rowGetter={i => rows[i]}
100
rowsCount={rows.length}
101
minHeight={400}
102
rowSelection={rowSelection}
103
/>
104
);
105
};
106
107
// Selection by unique keys
108
const KeyBasedSelection = () => {
109
const [selectedKeys, setSelectedKeys] = useState([]);
110
111
const rowSelection = {
112
showCheckbox: true,
113
enableShiftSelect: true,
114
onRowsSelected: (rows) => {
115
const newKeys = [...selectedKeys, ...rows.map(r => r.row.id)];
116
setSelectedKeys([...new Set(newKeys)]);
117
},
118
onRowsDeselected: (rows) => {
119
const deselectedKeys = rows.map(r => r.row.id);
120
setSelectedKeys(selectedKeys.filter(k => !deselectedKeys.includes(k)));
121
},
122
selectBy: {
123
keys: {
124
values: selectedKeys,
125
rowKey: 'id'
126
}
127
}
128
};
129
130
return (
131
<ReactDataGrid
132
columns={columns}
133
rowGetter={i => rows[i]}
134
rowsCount={rows.length}
135
minHeight={400}
136
rowSelection={rowSelection}
137
/>
138
);
139
};
140
```
141
142
### Cell Selection
143
144
Single cell and range selection for data manipulation and navigation.
145
146
```javascript { .api }
147
interface CellSelection {
148
/** Enable cell selection functionality */
149
enableCellSelect?: boolean;
150
/** Called when a cell is selected */
151
onCellSelected?: (position: Position) => void;
152
/** Called when a cell is deselected */
153
onCellDeSelected?: (position: Position) => void;
154
/** Cell navigation mode */
155
cellNavigationMode?: 'none' | 'loopOverRow' | 'changeRow';
156
}
157
158
interface Position {
159
/** Column index */
160
idx: number;
161
/** Row index */
162
rowIdx: number;
163
}
164
```
165
166
**Cell Selection Example:**
167
168
```javascript
169
const CellSelectionGrid = () => {
170
const [selectedCell, setSelectedCell] = useState(null);
171
172
const handleCellSelected = (position) => {
173
setSelectedCell(position);
174
console.log('Cell selected:', position);
175
};
176
177
const handleCellDeSelected = (position) => {
178
setSelectedCell(null);
179
console.log('Cell deselected:', position);
180
};
181
182
return (
183
<ReactDataGrid
184
columns={columns}
185
rowGetter={i => rows[i]}
186
rowsCount={rows.length}
187
minHeight={400}
188
enableCellSelect={true}
189
cellNavigationMode="changeRow"
190
onCellSelected={handleCellSelected}
191
onCellDeSelected={handleCellDeSelected}
192
/>
193
);
194
};
195
```
196
197
### Cell Range Selection
198
199
Multi-cell range selection for advanced data operations.
200
201
```javascript { .api }
202
interface CellRangeSelection {
203
/** Called when range selection begins */
204
onStart?: (selectedRange: SelectionRange) => void;
205
/** Called during range selection updates */
206
onUpdate?: (selectedRange: SelectionRange) => void;
207
/** Called when range selection is completed */
208
onComplete?: (selectedRange: SelectionRange) => void;
209
}
210
211
interface SelectionRange {
212
/** Top-left corner of selection */
213
topLeft: Position;
214
/** Bottom-right corner of selection */
215
bottomRight: Position;
216
}
217
```
218
219
**Range Selection Example:**
220
221
```javascript
222
const RangeSelectionGrid = () => {
223
const [selectionRange, setSelectionRange] = useState(null);
224
225
const cellRangeSelection = {
226
onStart: (range) => {
227
console.log('Range selection started:', range);
228
setSelectionRange(range);
229
},
230
onUpdate: (range) => {
231
console.log('Range selection updated:', range);
232
setSelectionRange(range);
233
},
234
onComplete: (range) => {
235
console.log('Range selection completed:', range);
236
// Perform operations on selected range
237
const selectedData = extractRangeData(range);
238
console.log('Selected data:', selectedData);
239
}
240
};
241
242
const extractRangeData = (range) => {
243
const data = [];
244
for (let rowIdx = range.topLeft.rowIdx; rowIdx <= range.bottomRight.rowIdx; rowIdx++) {
245
const row = rows[rowIdx];
246
const rowData = {};
247
for (let colIdx = range.topLeft.idx; colIdx <= range.bottomRight.idx; colIdx++) {
248
const column = columns[colIdx];
249
rowData[column.key] = row[column.key];
250
}
251
data.push(rowData);
252
}
253
return data;
254
};
255
256
return (
257
<ReactDataGrid
258
columns={columns}
259
rowGetter={i => rows[i]}
260
rowsCount={rows.length}
261
minHeight={400}
262
enableCellSelect={true}
263
cellRangeSelection={cellRangeSelection}
264
/>
265
);
266
};
267
```
268
269
### Event Handling
270
271
Comprehensive event system for handling user interactions and grid events.
272
273
```javascript { .api }
274
interface GridEvents {
275
// Row Events
276
/** Called when a row is clicked */
277
onRowClick?: (rowIdx: number, row: any, column: Column) => void;
278
/** Called when a row is double-clicked */
279
onRowDoubleClick?: (rowIdx: number, row: any, column: Column) => void;
280
/** Called when a row is selected */
281
onRowSelect?: (rowIdx: number, row: any) => void;
282
283
// Cell Events
284
/** Called when a cell is clicked */
285
onCellClick?: (position: Position, value: any, row: any) => void;
286
/** Called when a cell is double-clicked */
287
onCellDoubleClick?: (position: Position, value: any, row: any) => void;
288
/** Called when a cell context menu is triggered */
289
onCellContextMenu?: (position: Position, value: any, row: any) => void;
290
/** Called when a cell is expanded */
291
onCellExpand?: (args: CellExpandArgs) => void;
292
293
// Keyboard Events
294
/** Called on key down events */
295
onGridKeyDown?: (event: GridKeyboardEvent) => void;
296
/** Called on key up events */
297
onGridKeyUp?: (event: GridKeyboardEvent) => void;
298
299
// Data Events
300
/** Called when grid data is updated */
301
onGridRowsUpdated?: (event: GridRowsUpdatedEvent) => void;
302
/** Called when grid is sorted */
303
onGridSort?: (sortColumn: string, sortDirection: SortDirection) => void;
304
/** Called when grid is filtered */
305
onFilter?: (filter: Filter) => void;
306
307
// Layout Events
308
/** Called when grid is scrolled */
309
onScroll?: (scrollState: ScrollState) => void;
310
/** Called when a column is resized */
311
onColumnResize?: (idx: number, width: number) => void;
312
}
313
314
interface GridKeyboardEvent {
315
/** Row index */
316
rowIdx: number;
317
/** Column index */
318
idx: number;
319
/** Key that was pressed */
320
key: string;
321
/** Original keyboard event */
322
originalEvent: KeyboardEvent;
323
}
324
325
interface CellExpandArgs {
326
/** Row index */
327
rowIdx: number;
328
/** Column index */
329
idx: number;
330
/** Row data */
331
rowData: any;
332
/** Expand arguments */
333
expandArgs: any;
334
}
335
```
336
337
**Comprehensive Event Handling Example:**
338
339
```javascript
340
const EventHandlingGrid = () => {
341
const [eventLog, setEventLog] = useState([]);
342
343
const addEvent = (eventType, data) => {
344
const event = {
345
timestamp: new Date().toISOString(),
346
type: eventType,
347
data
348
};
349
setEventLog(prev => [event, ...prev.slice(0, 9)]); // Keep last 10 events
350
};
351
352
const handleRowClick = (rowIdx, row, column) => {
353
addEvent('Row Click', { rowIdx, row: row.name, column: column.name });
354
};
355
356
const handleRowDoubleClick = (rowIdx, row, column) => {
357
addEvent('Row Double Click', { rowIdx, row: row.name });
358
};
359
360
const handleCellClick = (position, value, row) => {
361
addEvent('Cell Click', { position, value, row: row.name });
362
};
363
364
const handleKeyDown = (event) => {
365
addEvent('Key Down', {
366
key: event.key,
367
position: { rowIdx: event.rowIdx, idx: event.idx }
368
});
369
};
370
371
const handleGridSort = (sortColumn, sortDirection) => {
372
addEvent('Sort', { sortColumn, sortDirection });
373
};
374
375
const handleScroll = (scrollState) => {
376
addEvent('Scroll', {
377
scrollTop: scrollState.scrollTop,
378
scrollLeft: scrollState.scrollLeft
379
});
380
};
381
382
return (
383
<div>
384
<ReactDataGrid
385
columns={columns}
386
rowGetter={i => rows[i]}
387
rowsCount={rows.length}
388
minHeight={400}
389
enableCellSelect={true}
390
onRowClick={handleRowClick}
391
onRowDoubleClick={handleRowDoubleClick}
392
onCellClick={handleCellClick}
393
onGridKeyDown={handleKeyDown}
394
onGridSort={handleGridSort}
395
onScroll={handleScroll}
396
/>
397
398
{/* Event Log Display */}
399
<div style={{ marginTop: '20px', padding: '10px', backgroundColor: '#f8f9fa' }}>
400
<h4>Event Log:</h4>
401
{eventLog.map((event, index) => (
402
<div key={index} style={{ fontSize: '12px', marginBottom: '4px' }}>
403
<strong>{event.type}</strong> - {event.timestamp} -
404
{JSON.stringify(event.data)}
405
</div>
406
))}
407
</div>
408
</div>
409
);
410
};
411
```
412
413
### Keyboard Navigation
414
415
Built-in keyboard shortcuts for navigation and interaction.
416
417
```javascript { .api }
418
interface KeyboardNavigation {
419
/** Cell navigation behavior */
420
cellNavigationMode?: 'none' | 'loopOverRow' | 'changeRow';
421
/** Enable automatic cell focus */
422
enableCellAutoFocus?: boolean;
423
}
424
```
425
426
**Keyboard Shortcuts:**
427
428
- **Arrow Keys**: Navigate between cells
429
- **Tab**: Move to next cell (with loopOverRow mode)
430
- **Shift+Tab**: Move to previous cell
431
- **Enter**: Start editing or confirm edit
432
- **Escape**: Cancel editing
433
- **Ctrl+C**: Copy selected cell(s)
434
- **Ctrl+V**: Paste copied content
435
- **Delete**: Clear selected cell content
436
- **Home**: Move to first column in row
437
- **End**: Move to last column in row
438
- **Page Up/Down**: Scroll grid up/down
439
- **Ctrl+Home**: Move to first cell
440
- **Ctrl+End**: Move to last cell
441
442
**Custom Keyboard Handling:**
443
444
```javascript
445
const CustomKeyboardGrid = () => {
446
const handleKeyDown = (event) => {
447
const { key, rowIdx, idx } = event;
448
449
switch (key) {
450
case 'F2':
451
// Custom: Start editing with F2
452
console.log('Start editing cell:', { rowIdx, idx });
453
event.originalEvent.preventDefault();
454
break;
455
456
case 'Delete':
457
// Custom: Clear cell content
458
console.log('Clear cell:', { rowIdx, idx });
459
// Implement clear logic
460
break;
461
462
case 'Insert':
463
// Custom: Insert new row
464
console.log('Insert new row at:', rowIdx);
465
// Implement insert logic
466
break;
467
468
default:
469
// Let grid handle other keys
470
break;
471
}
472
};
473
474
return (
475
<ReactDataGrid
476
columns={columns}
477
rowGetter={i => rows[i]}
478
rowsCount={rows.length}
479
minHeight={400}
480
enableCellSelect={true}
481
cellNavigationMode="changeRow"
482
onGridKeyDown={handleKeyDown}
483
/>
484
);
485
};
486
```
487
488
### Selection State Management
489
490
Managing selection state and integrating with application state.
491
492
```javascript
493
const SelectionStateGrid = () => {
494
const [rows, setRows] = useState(initialRows);
495
const [selectedRowIds, setSelectedRowIds] = useState([]);
496
const [selectedCell, setSelectedCell] = useState(null);
497
498
// Row selection handlers
499
const handleRowsSelected = (selectedRows) => {
500
const newIds = selectedRows.map(r => r.row.id);
501
setSelectedRowIds(prev => [...new Set([...prev, ...newIds])]);
502
};
503
504
const handleRowsDeselected = (deselectedRows) => {
505
const deselectedIds = deselectedRows.map(r => r.row.id);
506
setSelectedRowIds(prev => prev.filter(id => !deselectedIds.includes(id)));
507
};
508
509
// Cell selection handlers
510
const handleCellSelected = (position) => {
511
setSelectedCell(position);
512
};
513
514
// Programmatic selection methods
515
const selectAllRows = () => {
516
const allIds = rows.map(row => row.id);
517
setSelectedRowIds(allIds);
518
};
519
520
const clearSelection = () => {
521
setSelectedRowIds([]);
522
setSelectedCell(null);
523
};
524
525
const selectRowById = (id) => {
526
if (!selectedRowIds.includes(id)) {
527
setSelectedRowIds(prev => [...prev, id]);
528
}
529
};
530
531
return (
532
<div>
533
{/* Selection Controls */}
534
<div style={{ marginBottom: '10px' }}>
535
<button onClick={selectAllRows}>Select All</button>
536
<button onClick={clearSelection}>Clear Selection</button>
537
<span style={{ marginLeft: '20px' }}>
538
Selected: {selectedRowIds.length} rows
539
</span>
540
</div>
541
542
<ReactDataGrid
543
columns={columns}
544
rowGetter={i => rows[i]}
545
rowsCount={rows.length}
546
minHeight={400}
547
enableCellSelect={true}
548
rowSelection={{
549
showCheckbox: true,
550
enableShiftSelect: true,
551
onRowsSelected: handleRowsSelected,
552
onRowsDeselected: handleRowsDeselected,
553
selectBy: {
554
keys: {
555
values: selectedRowIds,
556
rowKey: 'id'
557
}
558
}
559
}}
560
onCellSelected={handleCellSelected}
561
/>
562
</div>
563
);
564
};
565
```