A high-performance React table component that efficiently renders large datasets using virtualization techniques. Only visible rows are rendered in the DOM, enabling smooth scrolling and interaction with datasets containing thousands of rows.
- Virtualization: Only renders visible rows for optimal performance
- Configurable Dataset Size: Test with 100 to 50,000 rows
- Adjustable Table Height: Customize viewport size (300px, 500px, 700px)
- Sticky Headers: Column headers remain visible while scrolling
- Custom Cell Rendering: Support for custom formatters and components
- TypeScript Support: Fully typed with generic column definitions
- Responsive Design: Clean, modern UI with proper spacing and borders
- React with TypeScript
- Vite for build tooling
- CSS Modules for styling
- Custom virtualization hook
- Node.js (v16 or higher)
- npm or yarn
# Install dependencies
npm install
# Start development server
npm run devnpm run buildsrc/
├── components/
│ ├── Demo/ # Main demo component with controls
│ ├── Table/ # Core table wrapper component
│ ├── TableHeader/ # Sticky header component
│ └── TableBody/ # Virtualized body with row rendering
├── hooks/
│ └── useVirtualization.ts # Custom hook for virtualization logic
├── types.ts # TypeScript type definitions
├── utils.ts # Data generation utilities
└── constant.ts # Configuration constants
import Table from './components/Table';
const columns = [
{ key: 'id', header: 'ID' },
{ key: 'name', header: 'Name' },
{
key: 'amount',
header: 'Amount',
render: (value) => `$${value.toFixed(2)}`
}
];
const data = [
{ id: 1, name: 'John Doe', amount: 1000 },
// ... more data
];
function App() {
return (
<Table
data={data}
columns={columns}
tableHeight={500}
rowHeight={40}
overScan={5}
/>
);
}type Column<ItemType> = {
key: keyof ItemType; // Data property key
header: string; // Display header text
width?: number; // Fixed column width in pixels
render?: (value, row) => React.ReactNode; // Custom cell renderer
};const columns = [
{
key: 'amount',
header: 'Amount',
render: (value) => (
<div style={{ color: 'red', fontWeight: 'bold' }}>
${value.toLocaleString()}
</div>
)
},
{
key: 'status',
header: 'Status',
render: (value, row) => (
<span className={`status-${value}`}>
{value.toUpperCase()}
</span>
)
}
];| Prop | Type | Default | Description |
|---|---|---|---|
data |
Array<{id: number}> |
Required | Array of data objects |
columns |
Column[] |
Required | Column definitions |
tableHeight |
number |
400 | Table viewport height in pixels |
rowHeight |
number |
40 | Height of each row in pixels |
overScan |
number |
5 | Extra rows to render outside viewport |
- Memory Efficient: Only visible rows exist in DOM
- Smooth Scrolling: Consistent performance regardless of dataset size
- Tested Scale: Handles 50,000+ rows without performance degradation
- Responsive: Maintains 60fps scrolling on modern devices
The virtualization logic calculates which rows should be rendered based on:
- Scroll Position: Current scroll offset
- Viewport Size: Visible area height
- Row Height: Fixed height per row
- Overscan: Buffer rows for smoother scrolling
const visibleStart = Math.floor(scrollTop / rowHeight);
const visibleEnd = visibleStart + Math.ceil(tableHeight / rowHeight);
const startIndex = Math.max(0, visibleStart - overScan);
const endIndex = Math.min(totalItems - 1, visibleEnd + overScan);- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
- Use consistent
rowHeightfor optimal virtualization - Implement
React.memofor complex cell renderers - Avoid inline styles in render functions
- Consider using
useMemofor expensive data transformations
MIT License - see LICENSE file for details
- Inspired by react-window and react-virtualized
- Sample data generated using Faker.js
- Built with modern React patterns and TypeScript