or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

core-components.mddynamic-content.mdindex.mdlayout-components.mdnavigation-components.mdspecialized-layouts.mdtable-components.mdutilities.md

navigation-components.mddocs/

0

# Navigation and Interaction Components

1

2

Components that add keyboard navigation, scroll synchronization, and window scrolling capabilities.

3

4

## Capabilities

5

6

### ArrowKeyStepper Component

7

8

Higher-order component that adds arrow key navigation to virtualized components, enabling keyboard-driven scrolling.

9

10

```javascript { .api }

11

/**

12

* Adds arrow key navigation to virtualized components

13

* @param props - ArrowKeyStepper configuration

14

*/

15

function ArrowKeyStepper(props: {

16

/** Function that renders the navigable component */

17

children: (params: {

18

onSectionRendered: (params: {columnStartIndex: number, columnStopIndex: number, rowStartIndex: number, rowStopIndex: number}) => void,

19

scrollToColumn: number,

20

scrollToRow: number

21

}) => React.Node;

22

/** Optional CSS class name */

23

className?: string;

24

/** Total number of columns */

25

columnCount: number;

26

/** Whether arrow key navigation is disabled */

27

disabled?: boolean;

28

/** Whether the component is controlled externally */

29

isControlled?: boolean;

30

/** Navigation mode: 'cells' for cell-by-cell, 'edges' for visible edge navigation */

31

mode?: 'cells' | 'edges';

32

/** Callback when scroll position changes */

33

onScrollToChange?: (params: {scrollToColumn: number, scrollToRow: number}) => void;

34

/** Total number of rows */

35

rowCount: number;

36

/** Column index to scroll to */

37

scrollToColumn?: number;

38

/** Row index to scroll to */

39

scrollToRow?: number;

40

}): React.Component;

41

```

42

43

**Usage Examples:**

44

45

```javascript

46

import React, { useState } from 'react';

47

import { ArrowKeyStepper, Grid, AutoSizer } from 'react-virtualized';

48

49

// Basic arrow key navigation with Grid

50

function NavigableGrid({ data }) {

51

const cellRenderer = ({ columnIndex, key, rowIndex, style }) => (

52

<div key={key} style={style} className="grid-cell">

53

{data[rowIndex][columnIndex]}

54

</div>

55

);

56

57

return (

58

<div style={{ height: 400, width: 600 }}>

59

<ArrowKeyStepper

60

columnCount={data[0].length}

61

rowCount={data.length}

62

mode="cells"

63

>

64

{({ onSectionRendered, scrollToColumn, scrollToRow }) => (

65

<AutoSizer>

66

{({ height, width }) => (

67

<Grid

68

cellRenderer={cellRenderer}

69

columnCount={data[0].length}

70

columnWidth={100}

71

height={height}

72

onSectionRendered={onSectionRendered}

73

rowCount={data.length}

74

rowHeight={50}

75

scrollToColumn={scrollToColumn}

76

scrollToRow={scrollToRow}

77

width={width}

78

/>

79

)}

80

</AutoSizer>

81

)}

82

</ArrowKeyStepper>

83

</div>

84

);

85

}

86

87

// Controlled arrow key navigation with external state

88

function ControlledNavigableGrid({ data, onPositionChange }) {

89

const [scrollToColumn, setScrollToColumn] = useState(0);

90

const [scrollToRow, setScrollToRow] = useState(0);

91

92

const handleScrollToChange = ({ scrollToColumn, scrollToRow }) => {

93

setScrollToColumn(scrollToColumn);

94

setScrollToRow(scrollToRow);

95

onPositionChange?.(scrollToRow, scrollToColumn);

96

};

97

98

const cellRenderer = ({ columnIndex, key, rowIndex, style }) => {

99

const isSelected = columnIndex === scrollToColumn && rowIndex === scrollToRow;

100

101

return (

102

<div

103

key={key}

104

style={{

105

...style,

106

backgroundColor: isSelected ? '#e3f2fd' : 'white',

107

border: isSelected ? '2px solid #2196f3' : '1px solid #ddd'

108

}}

109

className="grid-cell"

110

>

111

{data[rowIndex][columnIndex]}

112

</div>

113

);

114

};

115

116

return (

117

<div>

118

<div className="position-indicator">

119

Current Position: Row {scrollToRow + 1}, Column {scrollToColumn + 1}

120

</div>

121

122

<div style={{ height: 400, width: 600 }}>

123

<ArrowKeyStepper

124

columnCount={data[0].length}

125

rowCount={data.length}

126

isControlled={true}

127

scrollToColumn={scrollToColumn}

128

scrollToRow={scrollToRow}

129

onScrollToChange={handleScrollToChange}

130

mode="cells"

131

>

132

{({ onSectionRendered }) => (

133

<Grid

134

cellRenderer={cellRenderer}

135

columnCount={data[0].length}

136

columnWidth={80}

137

height={400}

138

onSectionRendered={onSectionRendered}

139

rowCount={data.length}

140

rowHeight={40}

141

scrollToColumn={scrollToColumn}

142

scrollToRow={scrollToRow}

143

width={600}

144

/>

145

)}

146

</ArrowKeyStepper>

147

</div>

148

</div>

149

);

150

}

151

```

152

153

### ScrollSync Component

154

155

Synchronizes scrolling between multiple virtualized components, useful for creating interfaces with linked scrollable areas.

156

157

```javascript { .api }

158

/**

159

* Synchronizes scrolling between multiple components

160

* @param props - ScrollSync configuration

161

*/

162

function ScrollSync(props: {

163

/** Function that renders synchronized scrollable components */

164

children: (params: {

165

clientHeight: number,

166

clientWidth: number,

167

onScroll: (params: {clientHeight: number, clientWidth: number, scrollHeight: number, scrollLeft: number, scrollTop: number, scrollWidth: number}) => void,

168

scrollHeight: number,

169

scrollLeft: number,

170

scrollTop: number,

171

scrollWidth: number

172

}) => React.Node;

173

}): React.Component;

174

```

175

176

**Usage Examples:**

177

178

```javascript

179

import React from 'react';

180

import { ScrollSync, Grid, List, AutoSizer } from 'react-virtualized';

181

182

// Synchronized scrolling between header and data grid

183

function SynchronizedTable({ headers, data }) {

184

const headerRenderer = ({ columnIndex, key, style }) => (

185

<div key={key} style={style} className="header-cell">

186

{headers[columnIndex]}

187

</div>

188

);

189

190

const cellRenderer = ({ columnIndex, key, rowIndex, style }) => (

191

<div key={key} style={style} className="data-cell">

192

{data[rowIndex][columnIndex]}

193

</div>

194

);

195

196

return (

197

<div style={{ height: 400, width: 800 }}>

198

<ScrollSync>

199

{({ clientHeight, clientWidth, onScroll, scrollLeft, scrollTop }) => (

200

<div>

201

{/* Fixed header */}

202

<div style={{ height: 50, width: clientWidth }}>

203

<Grid

204

cellRenderer={headerRenderer}

205

columnCount={headers.length}

206

columnWidth={150}

207

height={50}

208

rowCount={1}

209

rowHeight={50}

210

scrollLeft={scrollLeft}

211

width={clientWidth}

212

/>

213

</div>

214

215

{/* Scrollable data */}

216

<div style={{ height: 350, width: clientWidth }}>

217

<Grid

218

cellRenderer={cellRenderer}

219

columnCount={headers.length}

220

columnWidth={150}

221

height={350}

222

onScroll={onScroll}

223

rowCount={data.length}

224

rowHeight={40}

225

width={clientWidth}

226

/>

227

</div>

228

</div>

229

)}

230

</ScrollSync>

231

</div>

232

);

233

}

234

235

// Multi-panel synchronized scrolling

236

function MultiPanelView({ leftData, rightData }) {

237

const leftCellRenderer = ({ key, rowIndex, style }) => (

238

<div key={key} style={style} className="left-cell">

239

{leftData[rowIndex]}

240

</div>

241

);

242

243

const rightCellRenderer = ({ key, rowIndex, style }) => (

244

<div key={key} style={style} className="right-cell">

245

{rightData[rowIndex]}

246

</div>

247

);

248

249

return (

250

<div style={{ height: 500, width: '100%' }}>

251

<ScrollSync>

252

{({ onScroll, scrollTop }) => (

253

<AutoSizer>

254

{({ height, width }) => (

255

<div style={{ display: 'flex', height, width }}>

256

{/* Left panel */}

257

<div style={{ width: width * 0.3 }}>

258

<List

259

height={height}

260

onScroll={onScroll}

261

rowCount={leftData.length}

262

rowHeight={60}

263

rowRenderer={leftCellRenderer}

264

scrollTop={scrollTop}

265

width={width * 0.3}

266

/>

267

</div>

268

269

{/* Right panel */}

270

<div style={{ width: width * 0.7 }}>

271

<List

272

height={height}

273

onScroll={onScroll}

274

rowCount={rightData.length}

275

rowHeight={60}

276

rowRenderer={rightCellRenderer}

277

scrollTop={scrollTop}

278

width={width * 0.7}

279

/>

280

</div>

281

</div>

282

)}

283

</AutoSizer>

284

)}

285

</ScrollSync>

286

</div>

287

);

288

}

289

```

290

291

### WindowScroller Component

292

293

Enables virtualized components to be scrolled by the browser window instead of an internal scrollable container.

294

295

```javascript { .api }

296

/**

297

* Enables window-based scrolling for components

298

* @param props - WindowScroller configuration

299

*/

300

function WindowScroller(props: {

301

/** Function that renders the window-scrollable component */

302

children: (params: {

303

height: number,

304

isScrolling: boolean,

305

onChildScroll: (params: {scrollTop: number}) => void,

306

scrollTop: number,

307

width: number

308

}) => React.Node;

309

/** Callback when window resizes */

310

onResize?: (params: {height: number, width: number}) => void;

311

/** Callback when window scrolls */

312

onScroll?: (params: {scrollTop: number}) => void;

313

/** Custom scroll element (defaults to window) */

314

scrollElement?: Element;

315

/** Server-side rendering flag */

316

serverHeight?: number;

317

/** Server-side rendering flag */

318

serverWidth?: number;

319

}): React.Component;

320

321

/** Default timeout for scroll detection */

322

const IS_SCROLLING_TIMEOUT: number;

323

```

324

325

**Usage Examples:**

326

327

```javascript

328

import React from 'react';

329

import { WindowScroller, List, AutoSizer } from 'react-virtualized';

330

331

// Basic window scrolling list

332

function WindowScrolledList({ items }) {

333

const rowRenderer = ({ index, key, style }) => (

334

<div key={key} style={style} className="list-item">

335

<h3>Item {index}</h3>

336

<p>{items[index]}</p>

337

</div>

338

);

339

340

return (

341

<WindowScroller>

342

{({ height, isScrolling, onChildScroll, scrollTop, width }) => (

343

<AutoSizer disableHeight>

344

{({ width: autoWidth }) => (

345

<List

346

autoHeight

347

height={height}

348

isScrolling={isScrolling}

349

onScroll={onChildScroll}

350

rowCount={items.length}

351

rowHeight={120}

352

rowRenderer={rowRenderer}

353

scrollTop={scrollTop}

354

width={autoWidth}

355

/>

356

)}

357

</AutoSizer>

358

)}

359

</WindowScroller>

360

);

361

}

362

363

// Window scrolling with header and footer

364

function FullPageList({ items, headerContent, footerContent }) {

365

const rowRenderer = ({ index, key, style }) => (

366

<div key={key} style={style} className="full-page-item">

367

<div className="item-content">

368

<h4>{items[index].title}</h4>

369

<p>{items[index].description}</p>

370

<div className="item-meta">

371

<span>{items[index].date}</span>

372

<span>{items[index].author}</span>

373

</div>

374

</div>

375

</div>

376

);

377

378

return (

379

<div>

380

{/* Page header */}

381

<header style={{ height: 80, padding: 20, backgroundColor: '#f5f5f5' }}>

382

{headerContent}

383

</header>

384

385

{/* Window-scrolled content */}

386

<WindowScroller>

387

{({ height, isScrolling, onChildScroll, scrollTop, width }) => (

388

<div style={{ width: '100%' }}>

389

<List

390

autoHeight

391

height={height}

392

isScrolling={isScrolling}

393

onScroll={onChildScroll}

394

rowCount={items.length}

395

rowHeight={150}

396

rowRenderer={rowRenderer}

397

scrollTop={scrollTop}

398

width={width}

399

style={{ outline: 'none' }}

400

/>

401

</div>

402

)}

403

</WindowScroller>

404

405

{/* Page footer */}

406

<footer style={{ height: 60, padding: 20, backgroundColor: '#f5f5f5' }}>

407

{footerContent}

408

</footer>

409

</div>

410

);

411

}

412

413

// Window scrolling with scroll monitoring

414

function MonitoredWindowList({ items, onScrollChange }) {

415

const handleScroll = ({ scrollTop }) => {

416

onScrollChange?.(scrollTop);

417

};

418

419

const handleResize = ({ height, width }) => {

420

console.log(`Window resized to ${width}x${height}`);

421

};

422

423

const rowRenderer = ({ index, key, style }) => (

424

<div key={key} style={style} className="monitored-item">

425

<div className="item-number">#{index + 1}</div>

426

<div className="item-body">

427

<h3>{items[index].title}</h3>

428

<p>{items[index].content}</p>

429

</div>

430

</div>

431

);

432

433

return (

434

<div className="page-container">

435

<div className="content-header">

436

<h1>Scrollable Content</h1>

437

<p>This list scrolls with the browser window</p>

438

</div>

439

440

<WindowScroller

441

onScroll={handleScroll}

442

onResize={handleResize}

443

>

444

{({ height, isScrolling, onChildScroll, scrollTop, width }) => (

445

<div style={{ maxWidth: 800, margin: '0 auto' }}>

446

<List

447

autoHeight

448

height={height}

449

isScrolling={isScrolling}

450

onScroll={onChildScroll}

451

rowCount={items.length}

452

rowHeight={100}

453

rowRenderer={rowRenderer}

454

scrollTop={scrollTop}

455

width={Math.min(width, 800)}

456

/>

457

</div>

458

)}

459

</WindowScroller>

460

</div>

461

);

462

}

463

```