or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

component-handles.mdgrid-virtualization.mdgrouped-lists.mdindex.mdlist-virtualization.mdtable-virtualization.md

list-virtualization.mddocs/

0

# List Virtualization

1

2

Core list virtualization component that efficiently renders large datasets by only displaying visible items plus a configurable buffer. Automatically handles variable-sized items without manual measurements.

3

4

## Capabilities

5

6

### Virtuoso Component

7

8

Main virtualization component for rendering lists with automatic size detection and scroll optimization.

9

10

```typescript { .api }

11

/**

12

* Main virtualization component for rendering lists with automatic size detection

13

* @param props - Configuration options for the virtualized list

14

* @returns JSX.Element representing the virtualized list

15

*/

16

function Virtuoso<D = any, C = any>(props: VirtuosoProps<D, C>): JSX.Element;

17

18

interface VirtuosoProps<D, C> extends ListRootProps {

19

/** The data items to be rendered. If data is set, totalCount will be inferred from the length */

20

data?: readonly D[];

21

/** The total amount of items to be rendered */

22

totalCount?: number;

23

/** Set the callback to specify the contents of each item */

24

itemContent?: ItemContent<D, C>;

25

/** Use the components property for advanced customization of rendered elements */

26

components?: Components<D, C>;

27

/** Additional context available in custom components and content callbacks */

28

context?: C;

29

/** If specified, the component will use the function to generate the key property for each list item */

30

computeItemKey?: ComputeItemKey<D, C>;

31

32

/** Can be used to improve performance if the rendered items are of known size */

33

fixedItemHeight?: number;

34

/** By default, the component assumes the default item height from the first rendered item */

35

defaultItemHeight?: number;

36

37

/** If set to true, the list automatically scrolls to bottom if the total count is changed */

38

followOutput?: FollowOutput;

39

/** Gets called when the user scrolls to the end of the list */

40

endReached?: (index: number) => void;

41

/** Called when the user scrolls to the start of the list */

42

startReached?: (index: number) => void;

43

44

/** Called with the new set of items each time the list items are rendered due to scrolling */

45

rangeChanged?: (range: ListRange) => void;

46

/** Called with the new set of items each time the list items are rendered due to scrolling */

47

itemsRendered?: (items: ListItem<D>[]) => void;

48

49

/** Called with true / false when the list has reached the bottom / gets scrolled up */

50

atBottomStateChange?: (atBottom: boolean) => void;

51

/** Called with true / false when the list has reached the top / gets scrolled down */

52

atTopStateChange?: (atTop: boolean) => void;

53

54

/** Use when implementing inverse infinite scrolling */

55

firstItemIndex?: number;

56

/** Set to a value between 0 and totalCount - 1 to make the list start scrolled to that item */

57

initialTopMostItemIndex?: IndexLocationWithAlign | number;

58

/** Set this value to offset the initial location of the list */

59

initialScrollTop?: number;

60

61

/** Setting alignToBottom to true aligns the items to the bottom of the list if shorter than viewport */

62

alignToBottom?: boolean;

63

/** Uses the document scroller rather than wrapping the list in its own */

64

useWindowScroll?: boolean;

65

/** Pass a reference to a scrollable parent element */

66

customScrollParent?: HTMLElement;

67

68

/** Use to display placeholders if the user scrolls fast through the list */

69

scrollSeekConfiguration?: false | ScrollSeekConfiguration;

70

/** Set the overscan property to make the component chunk the rendering of new items on scroll */

71

overscan?: number | { main: number; reverse: number };

72

/** Set the increaseViewportBy property to artificially increase the viewport size */

73

increaseViewportBy?: number | { top: number; bottom: number };

74

75

/** Called when the list starts/stops scrolling */

76

isScrolling?: (isScrolling: boolean) => void;

77

/** Provides access to the root DOM element */

78

scrollerRef?: (ref: HTMLElement | null | Window) => any;

79

/** Pass a state obtained from getState() method to restore the list state */

80

restoreStateFrom?: StateSnapshot;

81

82

/** Set the amount of items to remain fixed at the top of the list */

83

topItemCount?: number;

84

/** Called when the total list height is changed due to new items or viewport resize */

85

totalListHeightChanged?: (height: number) => void;

86

/** Allows customizing the height/width calculation of Item elements */

87

itemSize?: SizeFunction;

88

/** Use for server-side rendering - if set, the list will render the specified amount of items */

89

initialItemCount?: number;

90

/** When set, turns the scroller into a horizontal list */

91

horizontalDirection?: boolean;

92

93

/** Implement this callback to adjust list position when total count changes */

94

scrollIntoViewOnChange?: (params: {

95

context: C;

96

totalCount: number;

97

scrollingInProgress: boolean;

98

}) => ScrollIntoViewLocation | null | undefined | false | void;

99

100

/** Set to customize the wrapper tag for header and footer components (default is 'div') */

101

headerFooterTag?: string;

102

103

/** Set to LogLevel.DEBUG to enable various diagnostics in the console */

104

logLevel?: LogLevel;

105

/** By default 4. Redefine to change how much away from the bottom the scroller can be */

106

atBottomThreshold?: number;

107

/** By default 0. Redefine to change how much away from the top the scroller can be */

108

atTopThreshold?: number;

109

/** When set, the resize observer will not use requestAnimationFrame to report size changes */

110

skipAnimationFrameInResizeObserver?: boolean;

111

}

112

113

type ItemContent<D, C> = (index: number, data: D, context: C) => React.ReactNode;

114

type ComputeItemKey<D, C> = (index: number, item: D, context: C) => React.Key;

115

type ListRootProps = Omit<React.HTMLProps<HTMLDivElement>, 'data' | 'ref'>;

116

117

type ScrollIntoViewLocation = FlatScrollIntoViewLocation | GroupedScrollIntoViewLocation;

118

119

interface FlatScrollIntoViewLocation extends ScrollIntoViewLocationOptions {

120

index: number;

121

}

122

123

interface GroupedScrollIntoViewLocation extends ScrollIntoViewLocationOptions {

124

groupIndex: number;

125

}

126

127

interface ScrollIntoViewLocationOptions {

128

align?: 'center' | 'end' | 'start';

129

behavior?: 'auto' | 'smooth';

130

calculateViewLocation?: CalculateViewLocation;

131

done?: () => void;

132

}

133

```

134

135

**Usage Examples:**

136

137

```typescript

138

import React from 'react';

139

import { Virtuoso } from 'react-virtuoso';

140

141

// Basic list with data array

142

function BasicList() {

143

const items = Array.from({ length: 10000 }, (_, i) => ({

144

id: i,

145

name: `Item ${i}`,

146

value: Math.random()

147

}));

148

149

return (

150

<Virtuoso

151

style={{ height: '400px' }}

152

data={items}

153

itemContent={(index, item) => (

154

<div style={{ padding: '12px', borderBottom: '1px solid #eee' }}>

155

<strong>{item.name}</strong>

156

<div>Value: {item.value.toFixed(3)}</div>

157

</div>

158

)}

159

/>

160

);

161

}

162

163

// List with totalCount (without data array)

164

function CountBasedList() {

165

return (

166

<Virtuoso

167

style={{ height: '400px' }}

168

totalCount={100000}

169

itemContent={(index) => (

170

<div style={{ padding: '12px' }}>

171

Item {index}

172

</div>

173

)}

174

/>

175

);

176

}

177

178

// List with infinite scrolling

179

function InfiniteList() {

180

const [items, setItems] = React.useState(

181

Array.from({ length: 100 }, (_, i) => `Item ${i}`)

182

);

183

184

const loadMore = () => {

185

setItems(prev => [

186

...prev,

187

...Array.from({ length: 50 }, (_, i) => `Item ${prev.length + i}`)

188

]);

189

};

190

191

return (

192

<Virtuoso

193

style={{ height: '400px' }}

194

data={items}

195

endReached={loadMore}

196

itemContent={(index, item) => (

197

<div style={{ padding: '12px' }}>

198

{item}

199

</div>

200

)}

201

/>

202

);

203

}

204

205

// List with custom components

206

function CustomComponentsList() {

207

const items = Array.from({ length: 1000 }, (_, i) => `Item ${i}`);

208

209

return (

210

<Virtuoso

211

style={{ height: '400px' }}

212

data={items}

213

components={{

214

Header: () => <div style={{ padding: '12px', fontWeight: 'bold' }}>Header</div>,

215

Footer: () => <div style={{ padding: '12px', fontWeight: 'bold' }}>Footer</div>,

216

EmptyPlaceholder: () => <div>No items to display</div>,

217

Item: ({ children, ...props }) => (

218

<div {...props} style={{ padding: '8px', margin: '4px', backgroundColor: '#f5f5f5' }}>

219

{children}

220

</div>

221

)

222

}}

223

itemContent={(index, item) => item}

224

/>

225

);

226

}

227

```

228

229

### Follow Output

230

231

Automatically scroll to bottom when new items are added, perfect for chat interfaces and live feeds.

232

233

```typescript { .api }

234

/**

235

* Configure automatic scrolling behavior when new items are added

236

*/

237

type FollowOutput = FollowOutputCallback | FollowOutputScalarType;

238

type FollowOutputCallback = (isAtBottom: boolean) => FollowOutputScalarType;

239

type FollowOutputScalarType = 'auto' | 'smooth' | boolean;

240

```

241

242

**Usage Example:**

243

244

```typescript

245

// Always follow output with smooth scrolling

246

<Virtuoso

247

followOutput="smooth"

248

data={messages}

249

itemContent={(index, message) => <div>{message.text}</div>}

250

/>

251

252

// Conditional follow output

253

<Virtuoso

254

followOutput={(isAtBottom) => {

255

// Only auto-scroll if user is already at bottom

256

return isAtBottom ? 'smooth' : false;

257

}}

258

data={messages}

259

itemContent={(index, message) => <div>{message.text}</div>}

260

/>

261

```

262

263

### Scroll Seek Configuration

264

265

Display placeholders during fast scrolling to improve performance.

266

267

```typescript { .api }

268

interface ScrollSeekConfiguration {

269

/** Callback to determine if the list should enter scroll seek mode */

270

enter: ScrollSeekToggle;

271

/** Callback to determine if the list should exit scroll seek mode */

272

exit: ScrollSeekToggle;

273

/** Called during scrolling in scroll seek mode - use to display a hint where the list is */

274

change?: (velocity: number, range: ListRange) => void;

275

}

276

277

type ScrollSeekToggle = (velocity: number, range: ListRange) => boolean;

278

279

interface ScrollSeekPlaceholderProps {

280

height: number;

281

index: number;

282

type: 'group' | 'item';

283

groupIndex?: number;

284

}

285

```

286

287

**Usage Example:**

288

289

```typescript

290

<Virtuoso

291

scrollSeekConfiguration={{

292

enter: (velocity) => Math.abs(velocity) > 200,

293

exit: (velocity) => Math.abs(velocity) < 30,

294

}}

295

components={{

296

ScrollSeekPlaceholder: ({ height, index }) => (

297

<div style={{ height, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>

298

Loading item {index}...

299

</div>

300

)

301

}}

302

data={items}

303

itemContent={(index, item) => <div>{item}</div>}

304

/>

305

```

306

307

### Performance Optimization

308

309

```typescript { .api }

310

/** Calculates the height of el, which will be the Item element in the DOM */

311

type SizeFunction = (el: HTMLElement, field: 'offsetHeight' | 'offsetWidth') => number;

312

313

interface StateSnapshot {

314

ranges: SizeRange[];

315

scrollTop: number;

316

}

317

318

interface SizeRange {

319

startIndex: number;

320

endIndex: number;

321

size: number;

322

}

323

324

type StateCallback = (state: StateSnapshot) => void;

325

```

326

327

**Usage Example:**

328

329

```typescript

330

function OptimizedList() {

331

const [state, setState] = React.useState<StateSnapshot | null>(null);

332

333

return (

334

<Virtuoso

335

// Fixed height for better performance

336

fixedItemHeight={50}

337

// Reduce overscan for memory efficiency

338

overscan={{ main: 5, reverse: 5 }}

339

// Restore previous state

340

restoreStateFrom={state}

341

// Custom size calculation

342

itemSize={(el) => el.getBoundingClientRect().height}

343

data={items}

344

itemContent={(index, item) => <div>{item}</div>}

345

/>

346

);

347

}

348

```

349

350

## Types

351

352

```typescript { .api }

353

interface ListItem<D> {

354

data?: D;

355

index: number;

356

offset: number;

357

size: number;

358

}

359

360

interface ListRange {

361

startIndex: number;

362

endIndex: number;

363

}

364

365

interface Item<D> {

366

data?: D;

367

index: number;

368

offset: number;

369

size: number;

370

}

371

372

enum LogLevel {

373

DEBUG,

374

INFO,

375

WARN,

376

ERROR

377

}

378

379

interface LocationOptions {

380

align?: 'center' | 'end' | 'start';

381

behavior?: 'auto' | 'smooth';

382

offset?: number;

383

}

384

385

interface FlatIndexLocationWithAlign extends LocationOptions {

386

index: 'LAST' | number;

387

}

388

389

type IndexLocationWithAlign = FlatIndexLocationWithAlign;

390

```