Marble UI
← Components

Virtualizer

Preview: 10k rows

Wrap a ListBox, GridList, Tree or Table to render only the visible rows. The collection inside needs a fixed height and overflow:auto.

Import

import { VirtualList } from '@marbleui/ui'

Props

<VirtualList>

PropTypeDefaultDescription
children *requiredReactNode—
estimatedRowHeightnumber—
gapnumber0
paddingnumber4
rowHeightnumber—Fixed row height in px (fast path). Omit with `estimatedRowHeight` for variable rows.

Accessibility

Keyboard interaction, focus management and ARIA semantics come from the underlying primitives: React Aria ListLayout · React Aria Virtualizer. Follow the primitive's docs for the full keyboard map.

Usage notes

Renders only the visible rows of a long list. Exported as VirtualList; wrap a ListBox, ListView, Tree or Table when it holds thousands of items.

<VirtualList rowHeight={36}>
  <ListBox aria-label="People" items={rows} className="h-72 overflow-auto">
    {(r) => <ListBoxItem id={r.id}>{r.name}</ListBoxItem>}
  </ListBox>
</VirtualList>
  • The wrapped collection needs a fixed height and overflow-auto, or nothing scrolls.
  • Use a fixed rowHeight for the fast path; for variable rows omit it and pass estimatedRowHeight. gap and padding (default 4) are in px.
  • Pass data through items with a render function, as in the example, rather than hand-written children.
Example source · show
import { useMemo } from 'react'
import { ListBox, ListBoxItem } from '../listbox'
import { VirtualList } from './virtualizer'

const first = ['Ada', 'Grace', 'Alan', 'Maya', 'Charles', 'Katherine', 'Linus', 'Margaret', 'Tim', 'Barbara']
const last = ['Lovelace', 'Hopper', 'Turing', 'Chen', 'Webb', 'Johnson', 'Torvalds', 'Hamilton', 'Berners-Lee', 'Liskov']

function TenThousand() {
  const rows = useMemo(() => Array.from({ length: 10_000 }, (_, i) => ({ id: i, name: `${first[i % 10]} ${last[(i * 7) % 10]}`, n: i + 1 })), [])
  return (
    <div className="flex flex-col gap-2">
      <VirtualList rowHeight={36}>
        <ListBox aria-label="10,000 people" selectionMode="multiple" items={rows} className="h-72 w-72 overflow-auto">
          {(r) => <ListBoxItem id={r.id} textValue={r.name}>#{r.n} · {r.name}</ListBoxItem>}
        </ListBox>
      </VirtualList>
      <span className="text-xs text-fg-subtle">10,000 rows, only ~10 in the DOM.</span>
    </div>
  )
}

export const styles = { '10k rows': TenThousand }

Source: packages/ui/src/virtualizer/virtualizer.tsx

Catalog

Category
collections
Priority
Core
Primitive
react-aria
React Aria
Virtualizer