virtua Documentation

repository·main·Indexed 23 days ago

https://github.com/inokawa/virtua

A zero-config, fast, and small (~3kB) virtual list and grid component library supporting React, Vue, Solid, Svelte, and Angular. It provides native support for dynamic item sizes, horizontal and RTL scrolling, window-level virtualization via WindowVirtualizer, and infinite scrolling. The library includes components like VList for standard lists, Virtualizer for custom layouts, and an experimental VGrid for 2D virtualization.

Tokens
27.2K
Snippets
13
Records
205
Agent score
86%

What's inside virtua

  1. Compare virtua features with other virtualization libraries

    main

    Use the following feature comparison to determine if virtua meets your project requirements compared to other popular virtualization libraries like react-virtuoso, react-window, react-virtualized, or @tanstack/react-virtual.

    Key strengths of virtua include:

    • Full Scroll Support: Built-in support for vertical, horizontal, and RTL (Right-to-Left) horizontal scrolling.
    • Advanced Scrolling: Supports reverse scroll, reverse bi-directional infinite scroll, smooth scroll, and scroll restoration.
    • Dynamic Sizing: Native support for both dynamic list sizes and dynamic item sizes.
    • Modern Web Support: Built-in SSR support and the ability to render React Server Components (RSC) as children.
    • Window Virtualization: Includes WindowVirtualizer for window-level scrolling.
    • Infinite Scroll: Built-in support for both standard and reverse infinite scrolling.

    Limitations:

    • Grid: 2D Grid virtualization is currently experimental (experimental_VGrid).
    • Table: Table support requires user customization.
    • Masonry: Not officially supported.
    • Browser Limits: Does not support displaying elements that exceed the browser's maximum element size limit.
  2. Use WindowVirtualizer in Angular

    main

    The WindowVirtualizer is a directive used to virtualize a list controlled by window scrolling. The host element acts as the container for the items. You can use attribute selectors to change the host tag, for example, using a <ul> element.

    To use it, apply the virtuaWindowVirtualizer directive to your container element and provide the data input.

  3. Use VList in Solid

    main

    In Solid, VList requires solid-js >= 1.0. Use the virtua/solid entry point. Pass data via the data prop and use a render function to access the item and index.

    import { VList } from "virtua/solid";
    
    export const App = () => {
      const sizes = [20, 40, 180, 77];
      const data = Array.from({ length: 1000 }).map((_, i) => sizes[i % 4]);
    
      return (
        <VList data={data} style={{ height: "800px" }}>
          {(d, i) => (
            <div
              style={{
                height: d + "px",
                "border-bottom": "solid 1px #ccc",
                background: "#fff",
              }}
            >
              {i()}
            </div>
          )}
        </VList>
      );
    };
  4. Restore scroll position using cache

    main

    You can restore the scroll position and state of a WindowVirtualizer by passing a CacheSnapshot to the cache prop on mount.

    Workflow:

    1. Obtain a snapshot using WindowVirtualizerHandle.getCache.
    2. Pass that snapshot to the cache prop when re-mounting the component.

    Critical Requirement: The length of the data array must be identical to the length of the array when the snapshot was taken, otherwise restoration may fail.

  5. Optimize performance for complex virtual scrolling

    main

    In scenarios with frequent re-renders or a large number of items, element creation can become a bottleneck. You can improve performance using these strategies:

    1. Memoize elements: Use useMemo to keep element instances stable across re-renders.
    2. Use Context: When passing state from parent to items, use React Context instead of props to avoid breaking memoization.
    3. Lazy rendering with Render Props: Use a render prop as children to create elements lazily. This reduces startup cost for >1000 items. Note that newly created elements from render props disable certain cached element optimizations, so it is recommended to use a memoized function or component.
    4. Adjust bufferSize: Decreasing the bufferSize prop can help if components are large and heavy.
    5. Handle Resizing: To prevent glitches during resize, set explicit height or min-height on items that resize frequently (e.g., lazy-loaded images).
    // Example: Memoizing elements with useMemo
    const elements = useMemo(
      () => tooLongArray.map((d) => <Component key={d.id} {...d} />),
      [tooLongArray],
    );
    const [position, setPosition] = useState(0);
    return (
      <div>
        <div>position: {position}</div>
        <VList onScroll={(offset) => setPosition(offset)}>{elements}</VList>
      </div>
    );
  6. Use VList in Vue

    main

    In Vue, VList requires vue >= 3.2. Use the virtua/vue entry point. You can pass data via the :data prop and use the #default slot to access the item and index.

    <script setup>
    import { VList } from "virtua/vue";
    
    const sizes = [20, 40, 180, 77];
    const data = Array.from({ length: 1000 }).map((_, i) => sizes[i % 4]);
    </script>
    
    <template>
      <VList :data="data" :style="{ height: '800px' }" #default="{ item, index }">
        <div
          :key="index"
          :style="{
            height: item + 'px',
            background: 'white',
            borderBottom: 'solid 1px #ccc',
          }"
        >
          {{ index }}
        </div>
      </VList>
    </template>
  7. Restore scroll position in VList using CacheSnapshot

    main

    To restore the scroll position of a VList after navigation, you can use the cache prop.

    1. Obtain a snapshot using VirtualizerHandle.getCache().
    2. Pass that snapshot back to the cache prop of the VList component on mount.

    Warning: The length of the data array must be exactly the same as it was when the snapshot was taken, otherwise restoration may fail.

  8. Use VList in React

    main

    The VList component is a drop-in replacement for scrollable lists in React. It requires react >= 16.14. If using ESM and webpack 5, use react >= 18 to avoid react/jsx-runtime errors.

    You can use VList in two ways:

    1. As children: Pass elements directly as children.
    2. With a data prop: Pass an array to data and use a render function to define how items are rendered.
    import { VList } from "virtua";
    
    // Using children
    export const App = () => {
      return (
        <VList style={{ height: 800 }}>
          {Array.from({ length: 1000 }).map((_, i) => (
            <div key={i} style={{ height: 50 }}>{i}</div>
          ))}
        </VList>
      );
    };
    
    // Using data prop and render function
    export const App = () => {
      const items = Array.from({ length: 1000 }).map(() => 50);
      return (
        <VList data={items} style={{ height: 800 }}>
          {(d, i) => (
            <div key={i} style={{ height: d }}>{i}</div>
          )}
        </VList>
      );
    };
  9. Implement reverse infinite scrolling with shift

    main

    Set the shift prop to true to maintain the scroll position relative to the end of the list rather than the start when items are added to or removed from the beginning. This is specifically useful for implementing reverse infinite scrolling.

    Warning: Set shift to false if you are adding/removing items from the middle or end of the list to avoid unexpected behavior.

  10. Use VList in Svelte

    main

    In Svelte, VList requires svelte >= 5.0. Use the virtua/svelte entry point. Pass data via the data prop and use the {#snippet children(item, index)} to define the item template.

    <script lang="ts">
      import { VList } from "virtua/svelte";
    
      const sizes = [20, 40, 180, 77];
      const data = Array.from({ length: 1000 }).map((_, i) => sizes[i % 4]);
    </script>
    
    <VList {data} style="height: 100vh;" getKey={(_, i) => i}>
      {#snippet children(item, index)}
        <div
          style="
            height: {item}px;
            background: white;
            border-bottom: solid 1px #ccc;
          "
        >
          {index}
        </div>
      {/snippet}
    </VList>
  11. Restore scroll position using Virtualizer cache

    main

    You can restore the scroll position and state of a Virtualizer by passing a CacheSnapshot to the cache input signal. This is useful for maintaining state after navigation.

    1. Obtain a snapshot using VirtualizerHandle.getCache().
    2. Pass that snapshot to the cache input when re-mounting the component.

    Warning: The length of the data array must be identical to the length of the array when the snapshot was taken for successful restoration.