or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

components.mdcore-grid.mdeditors.mdformatters.mdindex.mdselection.mdutilities.md

selection.mddocs/

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

```