Virtua

A zero-config, fast and small (~3kB) virtual list and grid component for Re...

README

virtua


A zero-config, fast and small (~3kB) virtual list and grid component for React.

If you want to check the difference with the alternatives right away, see comparison section.

Motivation


This project is a challenge to rethink virtualization. The goals are...

- Zero configuration: This library is designed to give the best performance without configuration. It also handles common hard things in the real world (dynamic size measurement, scroll position adjustment in bottom-up scrolling and imperative scrolling, etc).
- Fast: Scrolling without frame drop needs optimization in many aspects (reduce CPU usage, reduce GC, reduce layout recalculation, optimize with CSS, optimize for frameworks, etc). We are trying to combine the best of them.
- Small: Its bundle size should be small as much as possible to be friendly with modern web development. Currently each components are 3kB gzipped and the total is [4kB gzipped](https://bundlephobia.com/package/virtua).
- Flexible: Aiming to support many usecases - fixed size, dynamic size, horizontal scrolling, reverse scrolling, rtl direction, sticky, infinite scrolling, placeholder, scrollTo, dnd, table, and more. See live demo.
- Framework agnostic (WIP): Currently only for React but we could support Vue, Svelte, Solid, Angular, Web Components and more in the future.

Demo


https://inokawa.github.io/virtua/

Install


  1. ```sh
  2. npm install virtua
  3. ```

Requirements


- react >= 16.14

If you use ESM and webpack 5, use react >= 18 to avoid [Can't resolve react/jsx-runtime error](https://github.com/facebook/react/issues/20235).

If you use this lib in legacy browsers which does not have ResizeObserver, you should use polyfill.

Usage


Vertical scroll


  1. ```tsx
  2. import { VList } from "virtua";

  3. export const App = () => {
  4.   return (
  5.     <VList style={{ height: 800 }}>
  6.       {Array.from({ length: 1000 }).map((_, i) => (
  7.         <div
  8.           key={i}
  9.           style={{
  10.             height: Math.floor(Math.random() * 10) * 10 + 10,
  11.             borderBottom: "solid 1px gray",
  12.             background: "white",
  13.           }}
  14.         >
  15.           {i}
  16.         </div>
  17.       ))}
  18.     </VList>
  19.   );
  20. };
  21. ```

Horizontal scroll


  1. ```tsx
  2. import { VList } from "virtua";

  3. export const App = () => {
  4.   return (
  5.     <VList style={{ height: 400 }} horizontal>
  6.       {Array.from({ length: 1000 }).map((_, i) => (
  7.         <div
  8.           key={i}
  9.           style={{
  10.             width: Math.floor(Math.random() * 10) * 10 + 10,
  11.             borderRight: "solid 1px gray",
  12.             background: "white",
  13.           }}
  14.         >
  15.           {i}
  16.         </div>
  17.       ))}
  18.     </VList>
  19.   );
  20. };
  21. ```

Vertical and horizontal scroll


  1. ```tsx
  2. import { VGrid } from "virtua";

  3. export const App = () => {
  4.   return (
  5.     <VGrid style={{ height: 800 }} row={1000} col={500}>
  6.       {({ rowIndex, colIndex }) => (
  7.         <div
  8.           style={{
  9.             width: ((colIndex % 3) + 1) * 100,
  10.             border: "solid 1px gray",
  11.             background: "white",
  12.           }}
  13.         >
  14.           {rowIndex} / {colIndex}
  15.         </div>
  16.       )}
  17.     </VGrid>
  18.   );
  19. };
  20. ```

Window scroll


  1. ```tsx
  2. import { WVList } from "virtua";

  3. export const App = () => {
  4.   return (
  5.     <div style={{ padding: 200 }}>
  6.       <WVList>
  7.         {Array.from({ length: 1000 }).map((_, i) => (
  8.           <div
  9.             key={i}
  10.             style={{
  11.               height: Math.floor(Math.random() * 10) * 10 + 10,
  12.               borderBottom: "solid 1px gray",
  13.               background: "white",
  14.             }}
  15.           >
  16.             {i}
  17.           </div>
  18.         ))}
  19.       </WVList>
  20.     </div>
  21.   );
  22. };
  23. ```

React Server Components (RSC) support


This library is marked as a Client Component. You can render RSC as children of VList.

  1. ```tsx
  2. // page.tsx in App Router of Next.js

  3. export default async () => {
  4.   const articles = await fetchArticles();
  5.   return (
  6.     <div>
  7.       <div>This is Server Component</div>
  8.       <VList style={{ height: 300 }}>
  9.         {articles.map((a) => (
  10.           <div key={a.id} style={{ border: "solid 1px gray", height: 80 }}>
  11.             {a.content}
  12.           </div>
  13.         ))}
  14.       </VList>
  15.     </div>
  16.   );
  17. };
  18. ```

And see examples for more usages.

Documentation



Comparison


Benchmarks


WIP

Contribute


All contributions are welcome.
If you find a problem, feel free to create an issue or a PR.

Making a Pull Request


1. Clone this repo.
2. Run npm install.
3. Commit your fix.
4. Make a PR and confirm all the CI checks passed.