CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-react-virtualized

React components for efficiently rendering large lists and tabular data

Pending
Overview
Eval results
Files

specialized-layouts.mddocs/

Specialized Layout Components

Advanced components for complex layout requirements including arbitrary positioning, masonry layouts, and multi-grid arrangements.

Capabilities

Collection Component

Renders arbitrarily positioned and sized cells efficiently, perfect for complex layouts where items don't follow a regular grid pattern.

/**
 * Renders arbitrarily positioned cells efficiently
 * @param props - Collection configuration
 */
function Collection(props: {
  /** Aria label for accessibility */
  'aria-label'?: string;
  /** Total number of cells */
  cellCount: number;
  /** Cell rendering function */
  cellRenderer: (params: {index: number, key: string, style: object}) => React.Node;
  /** Function that returns position and size for each cell */
  cellSizeAndPositionGetter: (params: {index: number}) => {
    height: number,
    width: number,
    x: number,
    y: number
  };
  /** Optional CSS class name */
  className?: string;
  /** Height constraint for collection */
  height: number;
  /** Horizontal offset for scrolling */
  horizontalOverscanSize?: number;
  /** Renderer when no content is present */
  noContentRenderer?: () => React.Node;
  /** Callback when section is rendered */
  onSectionRendered?: (params: {indices: number[]}) => void;
  /** Scroll event callback */
  onScroll?: (params: {clientHeight: number, clientWidth: number, scrollHeight: number, scrollLeft: number, scrollTop: number, scrollWidth: number}) => void;
  /** Horizontal scroll offset */
  scrollLeft?: number;
  /** Vertical scroll offset */
  scrollTop?: number;
  /** Inline styles */
  style?: object;
  /** Vertical offset for scrolling */
  verticalOverscanSize?: number;
  /** Width constraint for collection */
  width: number;
}): React.Component;

Usage Examples:

import React from 'react';
import { Collection, AutoSizer } from 'react-virtualized';

// Basic Collection with random positioning
function RandomCollection({ items }) {
  const cellSizeAndPositionGetter = ({ index }) => {
    const item = items[index];
    return {
      height: item.height,
      width: item.width,
      x: item.x,
      y: item.y
    };
  };

  const cellRenderer = ({ index, key, style }) => (
    <div key={key} style={style} className="collection-cell">
      <div className="cell-content">
        <h4>{items[index].title}</h4>
        <p>{items[index].description}</p>
      </div>
    </div>
  );

  return (
    <div style={{ height: 600, width: 800 }}>
      <Collection
        cellCount={items.length}
        cellRenderer={cellRenderer}
        cellSizeAndPositionGetter={cellSizeAndPositionGetter}
        height={600}
        width={800}
      />
    </div>
  );
}

// Interactive Collection with drag-and-drop positioning
function InteractiveCollection({ items, onItemMove }) {
  const [positions, setPositions] = useState(
    items.reduce((acc, item, index) => {
      acc[index] = { x: item.x, y: item.y };
      return acc;
    }, {})
  );

  const cellSizeAndPositionGetter = ({ index }) => {
    const position = positions[index];
    return {
      height: 120,
      width: 200,
      x: position.x,
      y: position.y
    };
  };

  const cellRenderer = ({ index, key, style }) => {
    const handleMouseDown = (e) => {
      // Implement drag logic here
      const startX = e.clientX - positions[index].x;
      const startY = e.clientY - positions[index].y;

      const handleMouseMove = (e) => {
        const newX = e.clientX - startX;
        const newY = e.clientY - startY;
        
        setPositions(prev => ({
          ...prev,
          [index]: { x: newX, y: newY }
        }));
      };

      const handleMouseUp = () => {
        document.removeEventListener('mousemove', handleMouseMove);
        document.removeEventListener('mouseup', handleMouseUp);
        onItemMove?.(index, positions[index]);
      };

      document.addEventListener('mousemove', handleMouseMove);
      document.addEventListener('mouseup', handleMouseUp);
    };

    return (
      <div
        key={key}
        style={{
          ...style,
          cursor: 'move',
          border: '2px solid #ddd',
          borderRadius: '4px',
          backgroundColor: 'white'
        }}
        onMouseDown={handleMouseDown}
        className="draggable-cell"
      >
        <div style={{ padding: 10 }}>
          <h4>{items[index].title}</h4>
          <p>{items[index].content}</p>
        </div>
      </div>
    );
  };

  return (
    <div style={{ height: 600, width: 800, position: 'relative' }}>
      <Collection
        cellCount={items.length}
        cellRenderer={cellRenderer}
        cellSizeAndPositionGetter={cellSizeAndPositionGetter}
        height={600}
        width={800}
      />
    </div>
  );
}

Masonry Component

Renders dynamic, Pinterest-style masonry layouts where items flow into columns based on their heights.

/**
 * Renders Pinterest-style masonry layout
 * @param props - Masonry configuration
 */
function Masonry(props: {
  /** Total number of cells */
  cellCount: number;
  /** Cache for measuring cell dimensions */
  cellMeasurerCache?: CellMeasurerCache;
  /** Position manager for cell placement */
  cellPositioner: object;
  /** Cell rendering function */
  cellRenderer: (params: {index: number, key: string, parent: object, style: object}) => React.Node;
  /** Optional CSS class name */
  className?: string;
  /** Height constraint for masonry */
  height: number;
  /** Optional id attribute */
  id?: string;
  /** Callback when cells are rendered */
  onCellsRendered?: (params: {startIndex: number, stopIndex: number}) => void;
  /** Scroll event callback */
  onScroll?: (params: {clientHeight: number, scrollHeight: number, scrollTop: number}) => void;
  /** Number of extra cells to render */
  overscanByPixels?: number;
  /** Callback when scroll position changes */
  onScrollToChange?: (params: {align: string, scrollTop: number}) => void;
  /** Column index to scroll to */
  scrollToIndex?: number;
  /** Scroll alignment behavior */
  scrollToAlignment?: 'auto' | 'end' | 'start' | 'center';
  /** Vertical scroll offset */
  scrollTop?: number;
  /** Inline styles */
  style?: object;
  /** Tab index for focus */
  tabIndex?: number;
  /** Width constraint for masonry */
  width: number;
}): React.Component;

createMasonryCellPositioner Function

Creates a position manager for masonry layouts, handling the column-based positioning logic.

/**
 * Creates a cell positioner for masonry layouts
 * @param params - Positioner configuration
 */
function createMasonryCellPositioner(params: {
  /** Cache for cell measurements */
  cellMeasurerCache: CellMeasurerCache;
  /** Number of columns in the masonry */
  columnCount: number;
  /** Width of each column */
  columnWidth: number;
  /** Space between items */
  spacer?: number;
}): {
  /** Reset the positioner state */
  reset: (params: {columnCount: number, columnWidth: number, spacer?: number}) => void;
};

Usage Examples:

import React, { useMemo } from 'react';
import { 
  Masonry, 
  CellMeasurer, 
  CellMeasurerCache, 
  createMasonryCellPositioner,
  AutoSizer 
} from 'react-virtualized';

// Basic masonry layout
function BasicMasonry({ items }) {
  const cache = useMemo(() => new CellMeasurerCache({
    defaultHeight: 200,
    fixedWidth: true
  }), []);

  const cellPositioner = useMemo(() => 
    createMasonryCellPositioner({
      cellMeasurerCache: cache,
      columnCount: 3,
      columnWidth: 200,
      spacer: 10
    }), [cache]
  );

  const cellRenderer = ({ index, key, parent, style }) => (
    <CellMeasurer
      cache={cache}
      index={index}
      key={key}
      parent={parent}
    >
      <div style={style} className="masonry-item">
        <img
          src={items[index].imageUrl}
          alt={items[index].title}
          style={{ width: '100%', height: 'auto' }}
        />
        <div className="item-content">
          <h3>{items[index].title}</h3>
          <p>{items[index].description}</p>
        </div>
      </div>
    </CellMeasurer>
  );

  return (
    <div style={{ height: 600, width: 630 }}>
      <Masonry
        cellCount={items.length}
        cellMeasurerCache={cache}
        cellPositioner={cellPositioner}
        cellRenderer={cellRenderer}
        height={600}
        width={630}
      />
    </div>
  );
}

// Responsive masonry with dynamic columns
function ResponsiveMasonry({ items }) {
  const [columnCount, setColumnCount] = useState(3);
  
  const cache = useMemo(() => new CellMeasurerCache({
    defaultHeight: 250,
    fixedWidth: true
  }), []);

  const cellPositioner = useMemo(() => {
    const columnWidth = Math.floor((800 - (columnCount + 1) * 10) / columnCount);
    
    return createMasonryCellPositioner({
      cellMeasurerCache: cache,
      columnCount,
      columnWidth,
      spacer: 10
    });
  }, [cache, columnCount]);

  // Reset positioner when column count changes
  useEffect(() => {
    const columnWidth = Math.floor((800 - (columnCount + 1) * 10) / columnCount);
    cellPositioner.reset({
      columnCount,
      columnWidth,
      spacer: 10
    });
  }, [cellPositioner, columnCount]);

  const cellRenderer = ({ index, key, parent, style }) => {
    const item = items[index];
    
    return (
      <CellMeasurer
        cache={cache}
        index={index}
        key={key}
        parent={parent}
      >
        {({ measure, registerChild }) => (
          <div
            ref={registerChild}
            style={{
              ...style,
              borderRadius: '8px',
              overflow: 'hidden',
              backgroundColor: 'white',
              boxShadow: '0 2px 8px rgba(0,0,0,0.1)'
            }}
            className="responsive-masonry-item"
          >
            <img
              src={item.imageUrl}
              alt={item.title}
              onLoad={measure}
              style={{ width: '100%', height: 'auto', display: 'block' }}
            />
            <div style={{ padding: 12 }}>
              <h4 style={{ margin: '0 0 8px 0' }}>{item.title}</h4>
              <p style={{ margin: 0, color: '#666' }}>{item.description}</p>
              {item.tags && (
                <div style={{ marginTop: 8 }}>
                  {item.tags.map(tag => (
                    <span key={tag} className="tag">{tag}</span>
                  ))}
                </div>
              )}
            </div>
          </div>
        )}
      </CellMeasurer>
    );
  };

  return (
    <div>
      <div style={{ marginBottom: 20 }}>
        <label>
          Columns: 
          <select 
            value={columnCount} 
            onChange={(e) => setColumnCount(Number(e.target.value))}
          >
            <option value={2}>2</option>
            <option value={3}>3</option>
            <option value={4}>4</option>
            <option value={5}>5</option>
          </select>
        </label>
      </div>

      <div style={{ height: 600, width: 800 }}>
        <Masonry
          cellCount={items.length}
          cellMeasurerCache={cache}
          cellPositioner={cellPositioner}
          cellRenderer={cellRenderer}
          height={600}
          width={800}
        />
      </div>
    </div>
  );
}

MultiGrid Component

Grid component with fixed columns and/or rows, creating frozen panes similar to spreadsheet applications.

/**
 * Grid with fixed columns and/or rows
 * @param props - MultiGrid configuration
 */
function MultiGrid(props: {
  /** Optional CSS class name */
  className?: string;
  /** Class name for bottom-left grid */
  classNameBottomLeftGrid?: string;
  /** Class name for bottom-right grid */
  classNameBottomRightGrid?: string;
  /** Class name for top-left grid */
  classNameTopLeftGrid?: string;
  /** Class name for top-right grid */
  classNameTopRightGrid?: string;
  /** Total number of columns */
  columnCount: number;
  /** Fixed width or dynamic width function for columns */
  columnWidth: number | ((params: {index: number}) => number);
  /** Enable fixed columns on the right instead of left */
  enableFixedColumnScroll?: boolean;
  /** Enable fixed rows on the bottom instead of top */
  enableFixedRowScroll?: boolean;
  /** Number of fixed columns */
  fixedColumnCount?: number;
  /** Number of fixed rows */
  fixedRowCount?: number;
  /** Height constraint for grid */
  height: number;
  /** Renderer when no content is present */
  noContentRenderer?: () => React.Node;
  /** Callback when section is rendered */
  onSectionRendered?: (params: {columnStartIndex: number, columnStopIndex: number, rowStartIndex: number, rowStopIndex: number}) => void;
  /** Scroll event callback */
  onScroll?: (params: {clientHeight: number, clientWidth: number, scrollHeight: number, scrollLeft: number, scrollTop: number, scrollWidth: number}) => void;
  /** Number of extra columns to render */
  overscanColumnCount?: number;
  /** Number of extra rows to render */
  overscanRowCount?: number;
  /** Total number of rows */
  rowCount: number;
  /** Fixed height or dynamic height function for rows */
  rowHeight: number | ((params: {index: number}) => number);
  /** Cell rendering function */
  cellRenderer: (params: {columnIndex: number, key: string, rowIndex: number, style: object}) => React.Node;
  /** Column index to scroll to */
  scrollToColumn?: number;
  /** Row index to scroll to */
  scrollToRow?: number;
  /** Scroll alignment behavior */
  scrollToAlignment?: 'auto' | 'end' | 'start' | 'center';
  /** Horizontal scroll offset */
  scrollLeft?: number;
  /** Vertical scroll offset */
  scrollTop?: number;
  /** Inline styles */
  style?: object;
  /** Style for bottom-left grid */
  styleBottomLeftGrid?: object;
  /** Style for bottom-right grid */
  styleBottomRightGrid?: object;
  /** Style for top-left grid */
  styleTopLeftGrid?: object;
  /** Style for top-right grid */
  styleTopRightGrid?: object;
  /** Width constraint for grid */
  width: number;
}): React.Component;

Usage Examples:

import React from 'react';
import { MultiGrid, AutoSizer } from 'react-virtualized';

// Basic MultiGrid with frozen headers
function SpreadsheetGrid({ data, columnHeaders, rowHeaders }) {
  const cellRenderer = ({ columnIndex, key, rowIndex, style }) => {
    let content;
    let className = 'cell';

    if (columnIndex === 0 && rowIndex === 0) {
      // Top-left corner
      content = '';
      className = 'cell header-cell corner-cell';
    } else if (rowIndex === 0) {
      // Column headers
      content = columnHeaders[columnIndex - 1];
      className = 'cell header-cell column-header';
    } else if (columnIndex === 0) {
      // Row headers
      content = rowHeaders[rowIndex - 1];
      className = 'cell header-cell row-header';
    } else {
      // Data cells
      content = data[rowIndex - 1][columnIndex - 1];
      className = 'cell data-cell';
    }

    return (
      <div key={key} className={className} style={style}>
        {content}
      </div>
    );
  };

  return (
    <div style={{ height: 500, width: '100%' }}>
      <AutoSizer>
        {({ height, width }) => (
          <MultiGrid
            cellRenderer={cellRenderer}
            columnCount={columnHeaders.length + 1}
            columnWidth={({ index }) => index === 0 ? 80 : 120}
            fixedColumnCount={1}
            fixedRowCount={1}
            height={height}
            rowCount={data.length + 1}
            rowHeight={40}
            width={width}
            classNameTopLeftGrid="grid-top-left"
            classNameTopRightGrid="grid-top-right"
            classNameBottomLeftGrid="grid-bottom-left"
            classNameBottomRightGrid="grid-bottom-right"
          />
        )}
      </AutoSizer>
    </div>
  );
}

// Advanced MultiGrid with custom styling
function AdvancedMultiGrid({ salesData }) {
  const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'];
  const salespeople = ['Alice', 'Bob', 'Charlie', 'Diana'];

  const getColumnWidth = ({ index }) => {
    if (index === 0) return 100; // Names column
    return 80; // Data columns
  };

  const getRowHeight = ({ index }) => {
    if (index === 0) return 50; // Header row
    return 35; // Data rows
  };

  const cellRenderer = ({ columnIndex, key, rowIndex, style }) => {
    let content = '';
    let className = 'multigrid-cell';

    if (columnIndex === 0 && rowIndex === 0) {
      content = 'Salesperson';
      className += ' corner-header';
    } else if (rowIndex === 0) {
      content = months[columnIndex - 1];
      className += ' column-header';
    } else if (columnIndex === 0) {
      content = salespeople[rowIndex - 1];
      className += ' row-header';
    } else {
      const value = salesData[rowIndex - 1][columnIndex - 1];
      content = `$${value.toLocaleString()}`;
      className += ' data-cell';
      
      // Add performance-based styling
      if (value > 50000) className += ' high-performance';
      else if (value > 30000) className += ' medium-performance';
      else className += ' low-performance';
    }

    return (
      <div key={key} className={className} style={style}>
        {content}
      </div>
    );
  };

  return (
    <div className="sales-dashboard">
      <h2>Sales Performance Dashboard</h2>
      <div style={{ height: 400, width: 600 }}>
        <MultiGrid
          cellRenderer={cellRenderer}
          columnCount={months.length + 1}
          columnWidth={getColumnWidth}
          fixedColumnCount={1}
          fixedRowCount={1}
          height={400}
          rowCount={salespeople.length + 1}
          rowHeight={getRowHeight}
          width={600}
          styleBottomLeftGrid={{ borderRight: '2px solid #ddd' }}
          styleTopLeftGrid={{ borderRight: '2px solid #ddd', borderBottom: '2px solid #ddd' }}
          styleTopRightGrid={{ borderBottom: '2px solid #ddd' }}
        />
      </div>
    </div>
  );
}

Install with Tessl CLI

npx tessl i tessl/npm-react-virtualized

docs

core-components.md

dynamic-content.md

index.md

layout-components.md

navigation-components.md

specialized-layouts.md

table-components.md

utilities.md

tile.json