For AI agents: the complete documentation index is available at https://ifhover.github.io/leaf-ui/v/0.6.0/en/llms.txt, the full documentation bundle is available at https://ifhover.github.io/leaf-ui/v/0.6.0/en/llms-full.txt, and this page is available as Markdown at https://ifhover.github.io/leaf-ui/v/0.6.0/en/components/virtual-list.md.
  • English
  • VirtualList

    Browse large lists smoothly.

    Basic usage

    • Item 1
    • Item 2
    • Item 3
    • Item 4
    • Item 5
    • Item 6
    • Item 7
    • Item 8
    • Item 9
    • Item 10
    • Item 11
    basic.tsx
    import { VirtualList } from '@ifhover/leaf-ui';
    
    import { useState } from 'react';
    
    export function VirtualListBasic() {
      const [items] = useState(() =>
        Array.from({ length: 10000 }, (_, index) => ({
          id: String(index),
          name: `Item ${index + 1}`,
        })),
      );
      return (
        <VirtualList
          items={items}
          itemKey={(item) => item.id}
          height={240}
          estimateSize={44}
          renderItem={(item) => <div style={{ padding: '12px 16px' }}>{item.name}</div>}
        />
      );
    }
    

    More examples

    • #0

      Content with varying length.

    • #1

      Content with varying length. Content with varying length.

    • #2

      Content with varying length. Content with varying length. Content with varying length.

    • #3

      Content with varying length.

    • #4

      Content with varying length. Content with varying length.

    • #5

      Content with varying length. Content with varying length. Content with varying length.

    • #6

      Content with varying length.

    • #7

      Content with varying length. Content with varying length.

    • #8

      Content with varying length. Content with varying length. Content with varying length.

    advanced.tsx
    import { Button, Space, VirtualList } from '@ifhover/leaf-ui';
    
    import { useRef, useState } from 'react';
    
    export function VirtualListDynamic() {
      const list = useRef<import('@ifhover/leaf-ui').VirtualListHandle>(null);
      const [items] = useState(() =>
        Array.from({ length: 1000 }, (_, index) => ({
          id: String(index),
          text: 'Content with varying length. '.repeat((index % 3) + 1),
        })),
      );
      return (
        <Space direction="vertical" align="stretch">
          <Button variant="outline" onClick={() => list.current?.scrollToIndex(500, 'start')}>
            Go to item 501
          </Button>
          <VirtualList
            ref={list}
            items={items}
            itemKey={(item) => item.id}
            height={220}
            estimateSize={60}
            renderItem={(item) => (
              <div style={{ padding: 16 }}>
                <strong>#{item.id}</strong>
                <p style={{ margin: '4px 0' }}>{item.text}</p>
              </div>
            )}
          />
        </Space>
      );
    }
    

    Usage

    Keep itemKey stable. estimateSize is used initially; rows are measured afterward. SSR outputs a deterministic initial window that adjusts after mounting.

    Types

    Import these types for data, callbacks and refs.

    import type { VirtualListHandle, VirtualListProps } from '@ifhover/leaf-ui';

    VirtualListHandle API

    PropertyTypeDefaultDescription
    elementHTMLDivElement | nullRequiredScroll container element
    scrollToIndex(index: number, align?: 'auto' | 'start' | 'center' | 'end') => voidRequiredScroll to an item
    scrollToOffset(offset: number) => voidRequiredScroll to an offset

    VirtualListProps API

    PropertyTypeDefaultDescription
    itemsreadonly T[]RequiredItems; keep keys unique and stable
    itemKey(item: T, index: number) => KeyRequiredReturn a stable identifier
    renderItem(item: T, index: number) => ReactNodeRequiredCustom item renderer
    heightnumber320Height, numbers are in pixels
    estimateSizenumber | ((item: T, index: number) => number)40Estimated item size; actual size is measured
    overscannumber5Items rendered outside the visible range
    emptyContentReactNode—Empty list content
    horizontalbooleanfalseHorizontal virtual list