Blog>
Snippets

Implementing Dynamic Item Heights with TanStack Virtual

Showcase the implementation of a virtualized list that handles dynamic item heights efficiently, using the TanStack Virtual library.
import { useVirtual } from 'tanstack-virtual';
First, import the useVirtual hook from the TanStack Virtual library.
const listRef = React.useRef();
Create a ref for the scrolling container using React's useRef hook.
const rowVirtualizer = useVirtual({
  size: myItems.length, // Total number of items
  parentRef: listRef, // Scrolling container ref
  estimateSize: useCallback(() => 50, []), // Estimated item height
  measureRef: item => {
    // Measure callback to update an item's size dynamically
    if (item) {
      const height = item.getBoundingClientRect().height;
      rowVirtualizer.measureItemSize(index, height);
    }
  }
});
Initialize the row virtualizer with the useVirtual hook, providing the total number of items and the ref to the scrolling container. An estimated size for the items' height is provided for optimization. A measureRef callback function is also defined to dynamically measure the actual height of each item and update it using the measureItemSize method.
const renderRow = index => {
  const virtualRow = rowVirtualizer.virtualItems[index];
  const item = myItems[virtualRow.index];
  return (
    <div ref={rowVirtualizer.measureRef} style={{
      position: 'absolute',
      top: 0,
      left: 0,
      width: '100%',
      transform: `translateY(${virtualRow.start}px)`
    }}>
      {item.content}
    </div>
  );
};
Define a function to render each row. This function uses the virtual items provided by the row virtualizer. The items are absolutely positioned within the list, and the Y position is dynamically set based on the virtual item's start position. The measureRef is applied to each row element to capture and update the item's height dynamically.
return (
  <div ref={listRef} style={{
    height: '500px',
    overflow: 'auto'
  }}>
    <div style={{
      height: `${rowVirtualizer.totalSize}px`,
      position: 'relative'
    }}>
      {rowVirtualizer.virtualItems.map((virtualRow, index) => renderRow(index))}
    </div>
  </div>
);
Render the virtualized list inside a container with a fixed height and overflow set to auto to allow scrolling. Inside this container, another div is rendered, representing the virtual space. Its height is set to the total size of all items as calculated by the virtualizer. Each virtual item is then mapped to the renderRow function.