Beta Preview

Virtualizer

A Virtualizer renders a scrollable collection of data using customizable layouts. It supports very large collections by only rendering visible items to the DOM, reusing them as the user scrolls.

 
 
 
import {Virtualizer, ListLayout} from 'react-aria-components';
import {ListBox, ListBoxItem} from './ListBox';

let items = [];
for (let i = 0; i < 5000; i++) {
  items.push({id: i, name: `Item ${i}`});
}

<Virtualizer
  layout={ListLayout}
  layoutOptions={{rowHeight: 32, gap: 4, padding: 4}}
>
  <ListBox
    aria-label="Virtualized ListBox"
    selectionMode="multiple"
    items={items}
    style={{display: 'block', padding: 0}}>
    {item => <ListBoxItem style={{height: '100%', minHeight: 0}}>{item.name}</ListBoxItem>}
  </ListBox>
</Virtualizer>

Layouts

Virtualizer uses objects to determine the position and size of each item, and provide the list of currently visible items. When using a Virtualizer, all items are positioned by the Layout, and CSS layout properties such as flexbox and grid do not apply.

List

ListLayout supports layout of items in a vertical stack. Rows can be fixed or variable height. When using variable heights, set the estimatedRowHeight to a reasonable guess for how tall the rows will be on average. This allows the size of the scrollbar to be calculated.

 
 
import {Virtualizer, ListLayout} from 'react-aria-components';
import {GridList, GridListItem} from './GridList';

let lorem = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin sit amet tristique risus. In sit amet suscipit lorem. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. In condimentum imperdiet metus non condimentum. Duis eu velit et quam accumsan tempus at id velit. Duis elementum elementum purus, id tempus mauris posuere a. Nunc vestibulum sapien pellentesque lectus commodo ornare.'.split(' ');
let items = [];
for (let i = 0; i < 5000; i++) {
  let words = Math.max(2, Math.floor(Math.random() * 25));
  let name = lorem.slice(0, words).join(' ');
  items.push({id: i, name});
}

<Virtualizer
  layout={ListLayout}
  layoutOptions={{
    estimatedRowHeight: 75, 
    gap: 4, 
    padding: 4
  }}
>
  <GridList
    aria-label="Virtualized GridList"
    selectionMode="multiple"
    items={items}
    style={{display: 'block', padding: 0}}>
    {(item) => <GridListItem>{item.name}</GridListItem>}
  </GridList>
</Virtualizer>

Grid

GridLayout supports layout of items in an equal size grid. The items are sized between a minimum and maximum size depending on the width of the container. Make sure to set layout="grid" on the ListBox or GridList component as well so that keyboard navigation behavior is correct.

minItemSize 
maxItemSize 
minSpace 
 
preserveAspectRatio 
import {Virtualizer, GridLayout, Size, Text} from 'react-aria-components';
import {ListBox, ListBoxItem} from './ListBox';

let albums = []; for (let i = 0; i < 1000; i++) { albums.push({ id: i, ...albumOptions[i % albumOptions.length] }) } function Example(props) { return (
<div className="resizable"> <Virtualizer layout={GridLayout} layoutOptions={{ minItemSize: new Size(100, 140), minSpace: new Size(8, 8), maxColumns: Infinity, preserveAspectRatio: false }} {...props}> <ListBox layout="grid" aria-label="Virtualized grid layout" selectionMode="multiple" items={albums} style={{display: 'block', padding: 0, height: 300, width: '100%'}}> {item => ( <ListBoxItem textValue={item.title}> <img src={item.image} alt="" /> <Text slot="label" style={{fontSize: 12}}>{item.title}</Text> <Text slot="description">{item.artist}</Text> </ListBoxItem> )} </ListBox> </Virtualizer> </div> ); }

Waterfall

WaterfallLayout arranges variable height items in a column layout. The columns are sized between a minimum and maximum size depending on the width of the container.

minItemSize 
maxItemSize 
minSpace 
 
import {Virtualizer, WaterfallLayout, Size, Text} from 'react-aria-components';
import {ListBox, ListBoxItem} from './ListBox';

for (let i = 0; images.length < 500; i++) { images.push({...images[i % 30], id: String(i)});
} <Virtualizer layout={WaterfallLayout} layoutOptions={{ minItemSize: new Size(150, 150), minSpace: new Size(8, 8), maxColumns: Infinity }} > <ListBox layout="grid" aria-label="Virtualized waterfall layout" selectionMode="multiple" items={images} style={{display: 'block', padding: 0, height: 400, width: '100%'}}> {item => ( <ListBoxItem textValue={item.title}> <img src={item.image} alt="" style={{aspectRatio: item.aspectRatio, maxWidth: 'none'}} /> <Text slot="label" style={{fontSize: 12}}>{item.title}</Text> <Text slot="description">{item.user}</Text> </ListBoxItem> )} </ListBox> </Virtualizer>

Table

TableLayout provides layout of items in rows and columns, supporting virtualization of both horizontal and vertical scrolling. It should be used with the Table component. Rows can be fixed or variable height. When using variable heights, set the estimatedRowHeight to a reasonable guess for how tall the rows will be on average. This allows the size of the scrollbar to be calculated.

Foo
 
 
 
 
import {Virtualizer, TableLayout} from 'react-aria-components';
import {Cell, Column, Row, Table, TableBody, TableHeader} from './Table';

let rows = [];
for (let i = 0; i < 1000; i++) {
  rows.push({ id: i, foo: `Foo ${i}`, bar: `Bar ${i}`, baz: `Baz ${i}` });
}

<Virtualizer
  layout={TableLayout}
  layoutOptions={{
    rowHeight: 32, 
    headingHeight: 32, 
    padding: 4, 
    gap: 4
  }}
>
  <Table
    aria-label="Virtualized Table"
    selectionMode="multiple"
    style={{
      width: '100%',
      height: 300,
      overflow: 'auto',
      scrollPaddingTop: 38
    }}>
    <TableHeader
      style={{
        background: 'var(--gray-100)',
        width: '100%',
        height: '100%',
        borderRadius: 8,
        fontWeight: 'bold'
      }}>
      <Column isRowHeader>Foo</Column>
      <Column>Bar</Column>
      <Column>Baz</Column>
    </TableHeader>
    <TableBody items={rows}>
      {(item) => (
        <Row style={{width: 'inherit', height: 'inherit'}}>
          <Cell>{item.foo}</Cell>
          <Cell>{item.bar}</Cell>
          <Cell>{item.baz}</Cell>
        </Row>
      )}
    </TableBody>
  </Table>
</Virtualizer>

API

Virtualizer

NameType
childrenReactNode
The child collection to virtualize (e.g. ListBox, GridList, or Table).
layout<O> | <O>
The layout object that determines the position and size of the visible elements.
layoutOptionsO
Options for the layout.

ListLayout

NameTypeDefault
rowHeightnumberDefault: 48
The fixed height of a row in px.
estimatedRowHeightnumberDefault:
The estimated height of a row, when row heights are variable.
headingHeightnumberDefault: 48
The fixed height of a section header in px.
estimatedHeadingHeightnumberDefault:
The estimated height of a section header, when the height is variable.
loaderHeightnumberDefault: 48
The fixed height of a loader element in px. This loader is specifically for "load more" elements rendered when loading more rows at the root level or inside nested row/sections.
dropIndicatorThicknessnumberDefault: 2
The thickness of the drop indicator.
gapnumberDefault: 0
The gap between items.
paddingnumberDefault: 0
The padding around the list.

GridLayout

NameTypeDefault
minItemSizeDefault: 200 x 200
The minimum item size.
maxItemSizeDefault: Infinity
The maximum item size.
preserveAspectRatiobooleanDefault: false
Whether to preserve the aspect ratio of the minItemSize. By default, grid rows may have variable heights. When preserveAspectRatio is true, all rows will have equal heights.
minSpaceDefault: 18 x 18
The minimum space required between items.
maxHorizontalSpacenumberDefault: Infinity
The maximum allowed horizontal space between items.
maxColumnsnumberDefault: Infinity
The maximum number of columns.
dropIndicatorThicknessnumberDefault: 2
The thickness of the drop indicator.

WaterfallLayout

NameTypeDefault
minItemSizeDefault: 200 x 200
The minimum item size.
maxItemSizeDefault: Infinity
The maximum item size.
minSpaceDefault: 18 x 18
The minimum space required between items.
maxHorizontalSpacenumberDefault: Infinity
The maximum allowed horizontal space between items.
maxColumnsnumberDefault: Infinity
The maximum number of columns.
dropIndicatorThicknessnumberDefault: 2
The thickness of the drop indicator.

TableLayout

NameTypeDefault
rowHeightnumberDefault: 48
The fixed height of a row in px.
estimatedRowHeightnumberDefault:
The estimated height of a row, when row heights are variable.
headingHeightnumberDefault: 48
The fixed height of a section header in px.
estimatedHeadingHeightnumberDefault:
The estimated height of a section header, when the height is variable.
loaderHeightnumberDefault: 48
The fixed height of a loader element in px. This loader is specifically for "load more" elements rendered when loading more rows at the root level or inside nested row/sections.
dropIndicatorThicknessnumberDefault: 2
The thickness of the drop indicator.
gapnumberDefault: 0
The gap between items.
paddingnumberDefault: 0
The padding around the list.