Componentdata
VirtualList
Windowed list for fixed-height rows: scrollTop math, visible slice renders, spacer divs; smooth scroll.
Preview
Live Preview
Item 0
Item 1
Item 2
Item 3
Item 4
Item 5
Item 6
Item 7
Item 8
Item 9
Item 10
Installation
Tokens guide →Add to your project via CLI (zero dependencies, code you own):
npx bigbullui add virtual-listOr install the full npm package:
npm install bigbulluiUsage
import { VirtualList } from "@/components/ui/virtual-list"
<VirtualList
items={Array.from({ length: 100 }, (_, i) => i)}
itemHeight={40}
height={400}
render={(item) => <div key={item} className="p-2 bg-muted text-sm">Item {item}</div>} />Source code
virtual-list.tsxZero dependencies (only React + utils). Copy and paste directly into your project:
"use client";
import * as React from "react";
import { cn } from "./lib/utils";
export type VirtualListProps<T> = {
items: T[];
itemHeight: number;
height: number;
render: (item: T) => React.ReactNode;
};
export function VirtualList<T>({ items, itemHeight, height, render }: VirtualListProps<T>) {
const [scrollTop, setScrollTop] = React.useState(0);
const containerRef = React.useRef<HTMLDivElement>(null);
const visibleStart = Math.max(0, Math.floor(scrollTop / itemHeight) - 1);
const visibleEnd = Math.min(
items.length,
Math.ceil((scrollTop + height) / itemHeight) + 1,
);
const style = {
transform: `translateY(${scrollTop}px)`,
};
const spacerHeight = scrollTop + height + itemHeight;
return (
<div
ref={containerRef}
className={cn("relative overflow-auto", "motion-reduce:animate-none")}
onScroll={(e) => setScrollTop(e.currentTarget.scrollTop)}
style={{ height }}
>
<div
className={cn(
"relative",
"motion-reduce:animate-none",
"motion-reduce:transition-none",
)}
style={{
height,
transform: `translateY(${-scrollTop}px)`,
}}
>
{items.slice(visibleStart, visibleEnd).map((item, index) => (
<div
key={index}
className={cn("p-3 bg-card", "motion-reduce:animate-none")}
style={{ height: itemHeight }}
>
{render(item)}
</div>
))}
<div
className={cn("p-3 bg-muted", "motion-reduce:animate-none")}
style={{ height: spacerHeight }}
>
</div>
</div>
</div>
);
}Props
| Prop | Type | Description |
|---|---|---|
| items | T[] | List of items to render. |
| itemHeight | number | Height of each item in pixels. |
| height | number | Total visible height of the list container in pixels. |
| render | (item: T) => React.ReactNode | Renderer function for each item. |