CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-react-virtual

Hooks for virtualizing scrollable elements in React with support for rows, columns, and grids

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

index.mddocs/

React Virtual

React Virtual is a React hooks library that provides efficient virtualization capabilities for scrollable elements, enabling developers to render large lists and grids with optimal performance. The library offers a single headless hook (useVirtual) that supports row, column, and grid virtualization with flexible sizing options including fixed, variable, and dynamic measurements.

Package Information

  • Package Name: react-virtual
  • Package Type: npm
  • Language: JavaScript (with TypeScript support)
  • Installation: npm install react-virtual or yarn add react-virtual

Core Imports

import { useVirtual } from "react-virtual";

For CommonJS:

const { useVirtual } = require("react-virtual");

Basic Usage

import React from "react";
import { useVirtual } from "react-virtual";

function VirtualList() {
  const parentRef = React.useRef();

  const rowVirtualizer = useVirtual({
    size: 10000,
    parentRef: parentRef,
    estimateSize: React.useCallback(() => 35, []),
  });

  return (
    <div
      ref={parentRef}
      style={{
        height: "200px",
        width: "400px",
        overflow: "auto",
      }}
    >
      <div
        style={{
          height: `${rowVirtualizer.totalSize}px`,
          width: "100%",
          position: "relative",
        }}
      >
        {rowVirtualizer.items.map((virtualRow) => (
          <div
            key={virtualRow.index}
            style={{
              position: "absolute",
              top: 0,
              left: 0,
              width: "100%",
              height: `${virtualRow.size}px`,
              transform: `translateY(${virtualRow.start}px)`,
            }}
          >
            Row {virtualRow.index}
          </div>
        ))}
      </div>
    </div>
  );
}

Architecture

React Virtual is built around a single, powerful hook that manages virtualization state:

  • Measurement System: Tracks item sizes using either fixed estimates or dynamic measurements
  • Viewport Calculation: Determines which items are visible based on scroll position and container size
  • Overscan Management: Renders additional items beyond the visible area for smooth scrolling
  • Imperative Scrolling: Provides functions to programmatically scroll to specific items or offsets
  • Orientation Support: Handles both vertical (default) and horizontal virtualization

Capabilities

useVirtual Hook

The main virtualization hook that manages the rendering of large lists, grids, and columns with optimal performance.

/**
 * Main virtualization hook for efficient rendering of large datasets
 * @param options - Configuration object for virtualization behavior
 * @returns Object containing virtual items and control functions
 */
function useVirtual(options: VirtualOptions): VirtualResult;

interface VirtualOptions {
  /** Total number of items to virtualize (required) */
  size: number;
  /** Reference to the scrollable parent element (required) */
  parentRef: React.RefObject<HTMLElement>;
  /** Function to estimate size of each item (required, must be memoized with useCallback) */
  estimateSize: (index: number) => number;
  /** Number of items to render beyond visible area (default: 1) */
  overscan?: number;
  /** Enable horizontal virtualization using width/scrollLeft (default: false) */
  horizontal?: boolean;
}

interface VirtualResult {
  /** Array of currently visible virtual items */
  items: VirtualItem[];
  /** Total size of all virtualized content in pixels */
  totalSize: number;
  /** Function to scroll to a specific pixel offset */
  scrollToOffset: (offset: number) => void;
  /** Function to scroll to a specific item index */
  scrollToIndex: (index: number) => void;
}

interface VirtualItem {
  /** Zero-based index of the item */
  index: number;
  /** Starting position in pixels */
  start: number;
  /** Item size in pixels */
  size: number;
  /** Ending position in pixels */
  end: number;
  /** Ref callback for dynamic measurement */
  measureRef: (element: HTMLElement | null) => void;
}

Usage Patterns:

Row Virtualization (Vertical Lists):

const rowVirtualizer = useVirtual({
  size: 10000,
  parentRef: parentRef,
  estimateSize: React.useCallback(() => 35, []),
  overscan: 5,
});

Column Virtualization (Horizontal Lists):

const columnVirtualizer = useVirtual({
  horizontal: true,
  size: 1000,
  parentRef: parentRef,
  estimateSize: React.useCallback(() => 100, []),
  overscan: 5,
});

Grid Virtualization (2D Virtualization):

// Use two separate hooks for rows and columns
const rowVirtualizer = useVirtual({
  size: 10000,
  parentRef: parentRef,
  estimateSize: React.useCallback(() => 35, []),
  overscan: 5,
});

const columnVirtualizer = useVirtual({
  horizontal: true,
  size: 10000,
  parentRef: parentRef,
  estimateSize: React.useCallback(() => 100, []),
  overscan: 5,
});

// Render grid by mapping over both virtualizers
return (
  <div ref={parentRef} style={{ height: "500px", width: "500px", overflow: "auto" }}>
    <div
      style={{
        height: `${rowVirtualizer.totalSize}px`,
        width: `${columnVirtualizer.totalSize}px`,
        position: "relative",
      }}
    >
      {rowVirtualizer.items.map((virtualRow) => (
        <React.Fragment key={virtualRow.index}>
          {columnVirtualizer.items.map((virtualColumn) => (
            <div
              key={virtualColumn.index}
              style={{
                position: "absolute",
                top: 0,
                left: 0,
                width: `${virtualColumn.size}px`,
                height: `${virtualRow.size}px`,
                transform: `translateX(${virtualColumn.start}px) translateY(${virtualRow.start}px)`,
              }}
            >
              Cell {virtualRow.index}, {virtualColumn.index}
            </div>
          ))}
        </React.Fragment>
      ))}
    </div>
  </div>
);

Dynamic Measurement:

// For items with unknown sizes, use measureRef for runtime measurement
{rowVirtualizer.items.map((virtualRow) => (
  <div
    key={virtualRow.index}
    ref={virtualRow.measureRef}
    style={{
      position: "absolute",
      top: 0,
      left: 0,
      width: "100%",
      transform: `translateY(${virtualRow.start}px)`,
    }}
  >
    Content with dynamic height...
  </div>
))}

Imperative Scrolling:

// Scroll to specific item
const scrollToItem = (index) => {
  rowVirtualizer.scrollToIndex(index);
};

// Scroll to specific offset
const scrollToTop = () => {
  rowVirtualizer.scrollToOffset(0);
};

Key Features

  • Performance Optimized: Only renders visible items plus overscan, dramatically reducing DOM nodes
  • Flexible Sizing: Supports fixed, variable, and dynamic item sizing
  • Multi-directional: Handles vertical (default) and horizontal virtualization
  • Grid Support: Combine row and column virtualizers for 2D grids
  • Smooth Scrolling: Configurable overscan prevents visual gaps during fast scrolling
  • Imperative Control: Programmatic scrolling to specific items or positions
  • Framework Agnostic: Pure React hook with no additional dependencies beyond React
  • TypeScript Ready: Full type definitions for enhanced development experience

Error Handling

The hook expects:

  • estimateSize to be memoized with React.useCallback() to prevent unnecessary re-calculations
  • parentRef to reference an element with overflow: auto or overflow: scroll
  • size to be a positive integer representing the total number of items

If these requirements aren't met, the virtualization may not work correctly or performance may be degraded.

docs

index.md

tile.json