React components for efficiently rendering large lists and tabular data
—
Components that add keyboard navigation, scroll synchronization, and window scrolling capabilities.
Higher-order component that adds arrow key navigation to virtualized components, enabling keyboard-driven scrolling.
/**
* Adds arrow key navigation to virtualized components
* @param props - ArrowKeyStepper configuration
*/
function ArrowKeyStepper(props: {
/** Function that renders the navigable component */
children: (params: {
onSectionRendered: (params: {columnStartIndex: number, columnStopIndex: number, rowStartIndex: number, rowStopIndex: number}) => void,
scrollToColumn: number,
scrollToRow: number
}) => React.Node;
/** Optional CSS class name */
className?: string;
/** Total number of columns */
columnCount: number;
/** Whether arrow key navigation is disabled */
disabled?: boolean;
/** Whether the component is controlled externally */
isControlled?: boolean;
/** Navigation mode: 'cells' for cell-by-cell, 'edges' for visible edge navigation */
mode?: 'cells' | 'edges';
/** Callback when scroll position changes */
onScrollToChange?: (params: {scrollToColumn: number, scrollToRow: number}) => void;
/** Total number of rows */
rowCount: number;
/** Column index to scroll to */
scrollToColumn?: number;
/** Row index to scroll to */
scrollToRow?: number;
}): React.Component;Usage Examples:
import React, { useState } from 'react';
import { ArrowKeyStepper, Grid, AutoSizer } from 'react-virtualized';
// Basic arrow key navigation with Grid
function NavigableGrid({ data }) {
const cellRenderer = ({ columnIndex, key, rowIndex, style }) => (
<div key={key} style={style} className="grid-cell">
{data[rowIndex][columnIndex]}
</div>
);
return (
<div style={{ height: 400, width: 600 }}>
<ArrowKeyStepper
columnCount={data[0].length}
rowCount={data.length}
mode="cells"
>
{({ onSectionRendered, scrollToColumn, scrollToRow }) => (
<AutoSizer>
{({ height, width }) => (
<Grid
cellRenderer={cellRenderer}
columnCount={data[0].length}
columnWidth={100}
height={height}
onSectionRendered={onSectionRendered}
rowCount={data.length}
rowHeight={50}
scrollToColumn={scrollToColumn}
scrollToRow={scrollToRow}
width={width}
/>
)}
</AutoSizer>
)}
</ArrowKeyStepper>
</div>
);
}
// Controlled arrow key navigation with external state
function ControlledNavigableGrid({ data, onPositionChange }) {
const [scrollToColumn, setScrollToColumn] = useState(0);
const [scrollToRow, setScrollToRow] = useState(0);
const handleScrollToChange = ({ scrollToColumn, scrollToRow }) => {
setScrollToColumn(scrollToColumn);
setScrollToRow(scrollToRow);
onPositionChange?.(scrollToRow, scrollToColumn);
};
const cellRenderer = ({ columnIndex, key, rowIndex, style }) => {
const isSelected = columnIndex === scrollToColumn && rowIndex === scrollToRow;
return (
<div
key={key}
style={{
...style,
backgroundColor: isSelected ? '#e3f2fd' : 'white',
border: isSelected ? '2px solid #2196f3' : '1px solid #ddd'
}}
className="grid-cell"
>
{data[rowIndex][columnIndex]}
</div>
);
};
return (
<div>
<div className="position-indicator">
Current Position: Row {scrollToRow + 1}, Column {scrollToColumn + 1}
</div>
<div style={{ height: 400, width: 600 }}>
<ArrowKeyStepper
columnCount={data[0].length}
rowCount={data.length}
isControlled={true}
scrollToColumn={scrollToColumn}
scrollToRow={scrollToRow}
onScrollToChange={handleScrollToChange}
mode="cells"
>
{({ onSectionRendered }) => (
<Grid
cellRenderer={cellRenderer}
columnCount={data[0].length}
columnWidth={80}
height={400}
onSectionRendered={onSectionRendered}
rowCount={data.length}
rowHeight={40}
scrollToColumn={scrollToColumn}
scrollToRow={scrollToRow}
width={600}
/>
)}
</ArrowKeyStepper>
</div>
</div>
);
}Synchronizes scrolling between multiple virtualized components, useful for creating interfaces with linked scrollable areas.
/**
* Synchronizes scrolling between multiple components
* @param props - ScrollSync configuration
*/
function ScrollSync(props: {
/** Function that renders synchronized scrollable components */
children: (params: {
clientHeight: number,
clientWidth: number,
onScroll: (params: {clientHeight: number, clientWidth: number, scrollHeight: number, scrollLeft: number, scrollTop: number, scrollWidth: number}) => void,
scrollHeight: number,
scrollLeft: number,
scrollTop: number,
scrollWidth: number
}) => React.Node;
}): React.Component;Usage Examples:
import React from 'react';
import { ScrollSync, Grid, List, AutoSizer } from 'react-virtualized';
// Synchronized scrolling between header and data grid
function SynchronizedTable({ headers, data }) {
const headerRenderer = ({ columnIndex, key, style }) => (
<div key={key} style={style} className="header-cell">
{headers[columnIndex]}
</div>
);
const cellRenderer = ({ columnIndex, key, rowIndex, style }) => (
<div key={key} style={style} className="data-cell">
{data[rowIndex][columnIndex]}
</div>
);
return (
<div style={{ height: 400, width: 800 }}>
<ScrollSync>
{({ clientHeight, clientWidth, onScroll, scrollLeft, scrollTop }) => (
<div>
{/* Fixed header */}
<div style={{ height: 50, width: clientWidth }}>
<Grid
cellRenderer={headerRenderer}
columnCount={headers.length}
columnWidth={150}
height={50}
rowCount={1}
rowHeight={50}
scrollLeft={scrollLeft}
width={clientWidth}
/>
</div>
{/* Scrollable data */}
<div style={{ height: 350, width: clientWidth }}>
<Grid
cellRenderer={cellRenderer}
columnCount={headers.length}
columnWidth={150}
height={350}
onScroll={onScroll}
rowCount={data.length}
rowHeight={40}
width={clientWidth}
/>
</div>
</div>
)}
</ScrollSync>
</div>
);
}
// Multi-panel synchronized scrolling
function MultiPanelView({ leftData, rightData }) {
const leftCellRenderer = ({ key, rowIndex, style }) => (
<div key={key} style={style} className="left-cell">
{leftData[rowIndex]}
</div>
);
const rightCellRenderer = ({ key, rowIndex, style }) => (
<div key={key} style={style} className="right-cell">
{rightData[rowIndex]}
</div>
);
return (
<div style={{ height: 500, width: '100%' }}>
<ScrollSync>
{({ onScroll, scrollTop }) => (
<AutoSizer>
{({ height, width }) => (
<div style={{ display: 'flex', height, width }}>
{/* Left panel */}
<div style={{ width: width * 0.3 }}>
<List
height={height}
onScroll={onScroll}
rowCount={leftData.length}
rowHeight={60}
rowRenderer={leftCellRenderer}
scrollTop={scrollTop}
width={width * 0.3}
/>
</div>
{/* Right panel */}
<div style={{ width: width * 0.7 }}>
<List
height={height}
onScroll={onScroll}
rowCount={rightData.length}
rowHeight={60}
rowRenderer={rightCellRenderer}
scrollTop={scrollTop}
width={width * 0.7}
/>
</div>
</div>
)}
</AutoSizer>
)}
</ScrollSync>
</div>
);
}Enables virtualized components to be scrolled by the browser window instead of an internal scrollable container.
/**
* Enables window-based scrolling for components
* @param props - WindowScroller configuration
*/
function WindowScroller(props: {
/** Function that renders the window-scrollable component */
children: (params: {
height: number,
isScrolling: boolean,
onChildScroll: (params: {scrollTop: number}) => void,
scrollTop: number,
width: number
}) => React.Node;
/** Callback when window resizes */
onResize?: (params: {height: number, width: number}) => void;
/** Callback when window scrolls */
onScroll?: (params: {scrollTop: number}) => void;
/** Custom scroll element (defaults to window) */
scrollElement?: Element;
/** Server-side rendering flag */
serverHeight?: number;
/** Server-side rendering flag */
serverWidth?: number;
}): React.Component;
/** Default timeout for scroll detection */
const IS_SCROLLING_TIMEOUT: number;Usage Examples:
import React from 'react';
import { WindowScroller, List, AutoSizer } from 'react-virtualized';
// Basic window scrolling list
function WindowScrolledList({ items }) {
const rowRenderer = ({ index, key, style }) => (
<div key={key} style={style} className="list-item">
<h3>Item {index}</h3>
<p>{items[index]}</p>
</div>
);
return (
<WindowScroller>
{({ height, isScrolling, onChildScroll, scrollTop, width }) => (
<AutoSizer disableHeight>
{({ width: autoWidth }) => (
<List
autoHeight
height={height}
isScrolling={isScrolling}
onScroll={onChildScroll}
rowCount={items.length}
rowHeight={120}
rowRenderer={rowRenderer}
scrollTop={scrollTop}
width={autoWidth}
/>
)}
</AutoSizer>
)}
</WindowScroller>
);
}
// Window scrolling with header and footer
function FullPageList({ items, headerContent, footerContent }) {
const rowRenderer = ({ index, key, style }) => (
<div key={key} style={style} className="full-page-item">
<div className="item-content">
<h4>{items[index].title}</h4>
<p>{items[index].description}</p>
<div className="item-meta">
<span>{items[index].date}</span>
<span>{items[index].author}</span>
</div>
</div>
</div>
);
return (
<div>
{/* Page header */}
<header style={{ height: 80, padding: 20, backgroundColor: '#f5f5f5' }}>
{headerContent}
</header>
{/* Window-scrolled content */}
<WindowScroller>
{({ height, isScrolling, onChildScroll, scrollTop, width }) => (
<div style={{ width: '100%' }}>
<List
autoHeight
height={height}
isScrolling={isScrolling}
onScroll={onChildScroll}
rowCount={items.length}
rowHeight={150}
rowRenderer={rowRenderer}
scrollTop={scrollTop}
width={width}
style={{ outline: 'none' }}
/>
</div>
)}
</WindowScroller>
{/* Page footer */}
<footer style={{ height: 60, padding: 20, backgroundColor: '#f5f5f5' }}>
{footerContent}
</footer>
</div>
);
}
// Window scrolling with scroll monitoring
function MonitoredWindowList({ items, onScrollChange }) {
const handleScroll = ({ scrollTop }) => {
onScrollChange?.(scrollTop);
};
const handleResize = ({ height, width }) => {
console.log(`Window resized to ${width}x${height}`);
};
const rowRenderer = ({ index, key, style }) => (
<div key={key} style={style} className="monitored-item">
<div className="item-number">#{index + 1}</div>
<div className="item-body">
<h3>{items[index].title}</h3>
<p>{items[index].content}</p>
</div>
</div>
);
return (
<div className="page-container">
<div className="content-header">
<h1>Scrollable Content</h1>
<p>This list scrolls with the browser window</p>
</div>
<WindowScroller
onScroll={handleScroll}
onResize={handleResize}
>
{({ height, isScrolling, onChildScroll, scrollTop, width }) => (
<div style={{ maxWidth: 800, margin: '0 auto' }}>
<List
autoHeight
height={height}
isScrolling={isScrolling}
onScroll={onChildScroll}
rowCount={items.length}
rowHeight={100}
rowRenderer={rowRenderer}
scrollTop={scrollTop}
width={Math.min(width, 800)}
/>
</div>
)}
</WindowScroller>
</div>
);
}Install with Tessl CLI
npx tessl i tessl/npm-react-virtualized