Rooks
HooksExperimental Hooks

useVirtualList

Render a fixed-size virtual list with ready-to-use item styles.

About

Virtualize large fixed-size lists for vertical or horizontal scrolling. The hook exposes a container ref, total size, scroll helpers, and positioned virtual items ready to render.

Example

import { useVirtualList } from "rooks/experimental";

function Example() {
  const virtual = useVirtualList({
    items: Array.from({ length: 1_000 }, (_, index) => `Row ${index}`),
    itemSize: 36,
  });

  return (
    <div
      ref={virtual.containerRef}
      aria-label="Rows"
      style={{ height: 240, overflow: "auto", position: "relative" }}
    >
      <div role="list" style={virtual.innerStyle}>
        {virtual.items.map((row) => (
          <div
            key={row.key}
            role="listitem"
            aria-posinset={row.index + 1}
            aria-setsize={1_000}
            style={row.style}
          >
            {row.item}
          </div>
        ))}
      </div>
    </div>
  );
}

Return value

PropertyDescription
containerRefCallback ref for the scroll container.
innerStyleRelative-positioned spacer style with the full list size.
itemsVisible plus overscan items: { item, index, key, start, size, end, style }.
totalSizeitems.length * itemSize.
startIndexFirst visible item index before overscan.
endIndexLast visible item index before overscan.
scrollOffsetCurrent scrollTop or scrollLeft.
scrollToIndexClamps an index to the list and scrolls to index * itemSize.
scrollToOffsetSets the container's scroll offset; it is a no-op before the element is attached.

Parameters

OptionTypeDefaultDescription
itemsTItem[]requiredFull data set.
itemSizenumberrequiredFixed pixel size for every item; use a positive finite value.
overscannumber4Extra items rendered before and after the visible range.
orientation"vertical" | "horizontal""vertical"Selects height/top or width/left calculations.
initialIndexnumber0Index scrolled into position after the container attaches.
getItemKey(item, index) => string | numberitem indexStable React key for each virtual item.

Behavior and lifecycle

The hook composes useScroll and useSize, computes a fixed-size visible range, and renders that range plus normalized non-negative overscan with absolute positioning. Before measurement it treats the viewport as one item and starts at initialIndex. It scrolls to that index when the element attaches or the option changes. The composed listeners, observers, and scheduled measurements are cleaned up when the container changes or unmounts.

Compatibility and accessibility

The container needs a constrained size and overflow: auto; horizontal lists also need a width. SSR returns the deterministic one-item initial slice plus overscan. itemSize must be positive and finite or the hook throws; variable-size rows remain unsupported. Preserve list semantics (role, positions, set size, labels, and focus behavior as appropriate) because off-screen DOM items do not exist.

On this page