or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

index.mdreact-hooks.mdtypes-utilities.mdvirtualizer-engine.md

virtualizer-engine.mddocs/

0

# Virtualizer Core Engine

1

2

The core virtualization engine class that manages all aspects of virtual scrolling including item measurement, range calculation, scroll positioning, and DOM element lifecycle management.

3

4

## Capabilities

5

6

### Virtualizer Class

7

8

The main virtualization engine that handles all scrolling, measurement, and rendering calculations.

9

10

```typescript { .api }

11

/**

12

* Core virtualization engine for managing virtual scrolling

13

* @template TScrollElement - Type of the scroll container (Element or Window)

14

* @template TItemElement - Type of the virtualized item elements

15

*/

16

export class Virtualizer<TScrollElement extends Element | Window, TItemElement extends Element> {

17

constructor(opts: VirtualizerOptions<TScrollElement, TItemElement>);

18

19

// Configuration

20

setOptions(opts: VirtualizerOptions<TScrollElement, TItemElement>): void;

21

22

// Virtual item management

23

getVirtualItems(): Array<VirtualItem>;

24

getVirtualIndexes(): Array<number>;

25

calculateRange(): { startIndex: number; endIndex: number } | null;

26

27

// Measurement and sizing

28

measureElement(node: TItemElement | null | undefined): void;

29

resizeItem(index: number, size: number): void;

30

getTotalSize(): number;

31

measure(): void;

32

33

// Scroll control

34

scrollToIndex(index: number, options?: ScrollToIndexOptions): void;

35

scrollToOffset(toOffset: number, options?: ScrollToOffsetOptions): void;

36

scrollBy(delta: number, options?: ScrollToOffsetOptions): void;

37

38

// Position calculations

39

getOffsetForIndex(index: number, align?: ScrollAlignment): [number, ScrollAlignment] | undefined;

40

getOffsetForAlignment(toOffset: number, align: ScrollAlignment, itemSize?: number): number;

41

getVirtualItemForOffset(offset: number): VirtualItem | undefined;

42

43

// Element utilities

44

indexFromElement(node: TItemElement): number;

45

}

46

```

47

48

### Virtualizer Properties

49

50

The Virtualizer instance exposes several readonly properties for accessing current state:

51

52

```typescript { .api }

53

interface VirtualizerState {

54

/** The current scroll element being observed */

55

scrollElement: TScrollElement | null;

56

/** Reference to the target window object */

57

targetWindow: (Window & typeof globalThis) | null;

58

/** Whether the virtualizer is currently scrolling */

59

isScrolling: boolean;

60

/** Cache of measured virtual items */

61

measurementsCache: Array<VirtualItem>;

62

/** Current dimensions of the scroll container */

63

scrollRect: Rect | null;

64

/** Current scroll offset position */

65

scrollOffset: number | null;

66

/** Current scroll direction when scrolling */

67

scrollDirection: ScrollDirection | null;

68

/** Cache of DOM element references */

69

elementsCache: Map<Key, TItemElement>;

70

/** Current visible range of items */

71

range: { startIndex: number; endIndex: number } | null;

72

}

73

```

74

75

### Virtual Item Management

76

77

Methods for managing and accessing virtualized items:

78

79

```typescript { .api }

80

/**

81

* Get the current list of virtual items that should be rendered

82

* @returns Array of VirtualItem objects representing visible items

83

*/

84

getVirtualItems(): Array<VirtualItem>;

85

86

/**

87

* Get the indexes of items that need to be rendered (including overscan)

88

* @returns Array of item indexes to render

89

*/

90

getVirtualIndexes(): Array<number>;

91

92

/**

93

* Calculate the currently visible range of items

94

* @returns Object with startIndex and endIndex, or null if no items visible

95

*/

96

calculateRange(): { startIndex: number; endIndex: number } | null;

97

```

98

99

**Usage Examples:**

100

101

```typescript

102

import { Virtualizer } from '@tanstack/react-virtual';

103

104

// Create virtualizer instance

105

const virtualizer = new Virtualizer({

106

count: 1000,

107

getScrollElement: () => document.getElementById('scroll-container'),

108

estimateSize: () => 50,

109

scrollToFn: (offset, { behavior }, instance) => {

110

instance.scrollElement?.scrollTo({ top: offset, behavior });

111

},

112

observeElementRect: (instance, cb) => {

113

// ResizeObserver implementation

114

const observer = new ResizeObserver(entries => {

115

const entry = entries[0];

116

if (entry) {

117

cb({ width: entry.contentRect.width, height: entry.contentRect.height });

118

}

119

});

120

if (instance.scrollElement) observer.observe(instance.scrollElement as Element);

121

return () => observer.disconnect();

122

},

123

observeElementOffset: (instance, cb) => {

124

// Scroll event implementation

125

const handler = () => cb((instance.scrollElement as Element).scrollTop, true);

126

instance.scrollElement?.addEventListener('scroll', handler);

127

return () => instance.scrollElement?.removeEventListener('scroll', handler);

128

}

129

});

130

131

// Get items to render

132

const virtualItems = virtualizer.getVirtualItems();

133

virtualItems.forEach(item => {

134

console.log(`Render item ${item.index} at position ${item.start}`);

135

});

136

```

137

138

### Measurement and Sizing

139

140

Methods for handling dynamic item sizing and measurement:

141

142

```typescript { .api }

143

/**

144

* Measure a DOM element and update the virtualizer's size cache

145

* @param node - The DOM element to measure, or null to clean up disconnected elements

146

*/

147

measureElement(node: TItemElement | null | undefined): void;

148

149

/**

150

* Manually resize a specific item by index

151

* @param index - Index of the item to resize

152

* @param size - New size of the item in pixels

153

*/

154

resizeItem(index: number, size: number): void;

155

156

/**

157

* Get the total size of all virtualized content

158

* @returns Total height (vertical) or width (horizontal) in pixels

159

*/

160

getTotalSize(): number;

161

162

/**

163

* Force a complete remeasurement of all items

164

* Clears the size cache and triggers recalculation

165

*/

166

measure(): void;

167

```

168

169

**Usage Examples:**

170

171

```typescript

172

// Measure element during render

173

function VirtualItem({ virtualizer, item, data }) {

174

return (

175

<div

176

data-index={item.index}

177

ref={(node) => virtualizer.measureElement(node)}

178

style={{

179

position: 'absolute',

180

top: 0,

181

left: 0,

182

width: '100%',

183

transform: `translateY(${item.start}px)`,

184

}}

185

>

186

{data[item.index]}

187

</div>

188

);

189

}

190

191

// Manual resizing after content change

192

function updateItemContent(virtualizer: Virtualizer, index: number, newContent: string) {

193

// Update content...

194

195

// If we know the new size, update it directly

196

const newSize = estimateContentHeight(newContent);

197

virtualizer.resizeItem(index, newSize);

198

199

// Or trigger complete remeasurement

200

virtualizer.measure();

201

}

202

203

// Get container height for styling

204

function VirtualContainer({ virtualizer }) {

205

const totalSize = virtualizer.getTotalSize();

206

207

return (

208

<div style={{

209

height: `${totalSize}px`,

210

position: 'relative',

211

}}>

212

{/* Virtual items */}

213

</div>

214

);

215

}

216

```

217

218

### Scroll Control

219

220

Methods for programmatically controlling scroll position:

221

222

```typescript { .api }

223

/**

224

* Scroll to a specific item index

225

* @param index - Index of the item to scroll to

226

* @param options - Scroll behavior options

227

*/

228

scrollToIndex(index: number, options?: ScrollToIndexOptions): void;

229

230

/**

231

* Scroll to a specific offset position

232

* @param toOffset - Target scroll position in pixels

233

* @param options - Scroll behavior options

234

*/

235

scrollToOffset(toOffset: number, options?: ScrollToOffsetOptions): void;

236

237

/**

238

* Scroll by a relative amount

239

* @param delta - Amount to scroll in pixels (positive = down/right, negative = up/left)

240

* @param options - Scroll behavior options

241

*/

242

scrollBy(delta: number, options?: ScrollToOffsetOptions): void;

243

244

interface ScrollToIndexOptions {

245

/** How to align the item within the viewport */

246

align?: ScrollAlignment;

247

/** Scroll behavior (smooth or instant) */

248

behavior?: ScrollBehavior;

249

}

250

251

interface ScrollToOffsetOptions {

252

/** How to align the offset within the viewport */

253

align?: ScrollAlignment;

254

/** Scroll behavior (smooth or instant) */

255

behavior?: ScrollBehavior;

256

}

257

258

type ScrollAlignment = 'start' | 'center' | 'end' | 'auto';

259

type ScrollBehavior = 'auto' | 'smooth';

260

```

261

262

**Usage Examples:**

263

264

```typescript

265

// Scroll to specific items

266

function scrollToTop(virtualizer: Virtualizer) {

267

virtualizer.scrollToIndex(0, { align: 'start' });

268

}

269

270

function scrollToBottom(virtualizer: Virtualizer) {

271

virtualizer.scrollToIndex(virtualizer.options.count - 1, { align: 'end' });

272

}

273

274

function scrollToMiddle(virtualizer: Virtualizer) {

275

const middleIndex = Math.floor(virtualizer.options.count / 2);

276

virtualizer.scrollToIndex(middleIndex, { align: 'center', behavior: 'smooth' });

277

}

278

279

// Scroll by relative amounts

280

function scrollPage(virtualizer: Virtualizer, direction: 'up' | 'down') {

281

const pageSize = virtualizer.scrollRect?.height ?? 400;

282

const delta = direction === 'down' ? pageSize : -pageSize;

283

virtualizer.scrollBy(delta, { behavior: 'smooth' });

284

}

285

286

// Scroll to specific positions

287

function scrollToPosition(virtualizer: Virtualizer, position: number) {

288

virtualizer.scrollToOffset(position, { align: 'start' });

289

}

290

```

291

292

### Position Calculations

293

294

Methods for calculating positions and offsets:

295

296

```typescript { .api }

297

/**

298

* Get the scroll offset needed to show a specific item

299

* @param index - Index of the item

300

* @param align - How to align the item (default: 'auto')

301

* @returns Tuple of [offset, actualAlignment] or undefined if item not found

302

*/

303

getOffsetForIndex(index: number, align?: ScrollAlignment): [number, ScrollAlignment] | undefined;

304

305

/**

306

* Calculate the aligned offset for a given position

307

* @param toOffset - Target offset position

308

* @param align - Alignment mode

309

* @param itemSize - Size of the item being aligned (optional)

310

* @returns Calculated offset position

311

*/

312

getOffsetForAlignment(toOffset: number, align: ScrollAlignment, itemSize?: number): number;

313

314

/**

315

* Find the virtual item at a specific scroll offset

316

* @param offset - Scroll offset position

317

* @returns VirtualItem at that position, or undefined if none found

318

*/

319

getVirtualItemForOffset(offset: number): VirtualItem | undefined;

320

```

321

322

### Element Utilities

323

324

Utility methods for working with DOM elements:

325

326

```typescript { .api }

327

/**

328

* Extract the item index from a DOM element's data-index attribute

329

* @param node - The DOM element to inspect

330

* @returns The item index, or -1 if not found or invalid

331

*/

332

indexFromElement(node: TItemElement): number;

333

```

334

335

**Usage Examples:**

336

337

```typescript

338

// Handle click events on virtual items

339

function handleItemClick(event: MouseEvent, virtualizer: Virtualizer) {

340

const element = event.target as HTMLElement;

341

const index = virtualizer.indexFromElement(element);

342

if (index >= 0) {

343

console.log(`Clicked item at index ${index}`);

344

}

345

}

346

347

// Find item at current scroll position

348

function getCurrentItem(virtualizer: Virtualizer) {

349

const currentOffset = virtualizer.scrollOffset ?? 0;

350

const item = virtualizer.getVirtualItemForOffset(currentOffset);

351

return item;

352

}

353

354

// Calculate positions for custom scroll animations

355

function animateToItem(virtualizer: Virtualizer, targetIndex: number) {

356

const offsetInfo = virtualizer.getOffsetForIndex(targetIndex, 'center');

357

if (offsetInfo) {

358

const [targetOffset] = offsetInfo;

359

// Implement custom animation to targetOffset

360

animateScrollTo(targetOffset);

361

}

362

}

363

```

364

365

## Configuration and Options

366

367

The Virtualizer requires comprehensive configuration through `VirtualizerOptions`:

368

369

```typescript { .api }

370

export interface VirtualizerOptions<TScrollElement extends Element | Window, TItemElement extends Element> {

371

// Required configuration

372

count: number;

373

getScrollElement: () => TScrollElement | null;

374

estimateSize: (index: number) => number;

375

scrollToFn: (offset: number, options: ScrollOptions, instance: Virtualizer<TScrollElement, TItemElement>) => void;

376

observeElementRect: (instance: Virtualizer<TScrollElement, TItemElement>, cb: (rect: Rect) => void) => void | (() => void);

377

observeElementOffset: (instance: Virtualizer<TScrollElement, TItemElement>, cb: (offset: number, isScrolling: boolean) => void) => void | (() => void);

378

379

// Optional configuration with defaults

380

debug?: boolean; // false

381

initialRect?: Rect; // { width: 0, height: 0 }

382

onChange?: (instance: Virtualizer<TScrollElement, TItemElement>, sync: boolean) => void;

383

measureElement?: (element: TItemElement, entry: ResizeObserverEntry | undefined, instance: Virtualizer<TScrollElement, TItemElement>) => number;

384

overscan?: number; // 1

385

horizontal?: boolean; // false

386

paddingStart?: number; // 0

387

paddingEnd?: number; // 0

388

scrollPaddingStart?: number; // 0

389

scrollPaddingEnd?: number; // 0

390

initialOffset?: number | (() => number); // 0

391

getItemKey?: (index: number) => Key; // (index) => index

392

rangeExtractor?: (range: Range) => Array<number>; // defaultRangeExtractor

393

scrollMargin?: number; // 0

394

gap?: number; // 0

395

indexAttribute?: string; // 'data-index'

396

initialMeasurementsCache?: Array<VirtualItem>; // []

397

lanes?: number; // 1

398

isScrollingResetDelay?: number; // 150

399

useScrollendEvent?: boolean; // false

400

enabled?: boolean; // true

401

isRtl?: boolean; // false

402

useAnimationFrameWithResizeObserver?: boolean; // false

403

}

404

405

export interface ScrollOptions {

406

adjustments?: number;

407

behavior?: ScrollBehavior;

408

}

409

```

410

411

## Performance Considerations

412

413

### Efficient Range Calculation

414

415

The Virtualizer uses binary search algorithms to efficiently calculate visible ranges even with thousands of items.

416

417

### Memory Management

418

419

- Automatically cleans up disconnected DOM elements

420

- Manages ResizeObserver connections efficiently

421

- Caches measurements to avoid unnecessary calculations

422

423

### Scroll Performance

424

425

- Debounced scroll end detection

426

- Optimized for both mouse wheel and touch scrolling

427

- Support for native `scrollend` events where available