Skip to content

useVirtualList

Virtualizes a long list inside a scroll container.

Virtualizes a long list inside a scroll container.

Import

import { useVirtualList } from '@kamod-ch/hooks'

Live demo

Basic demo

Virtualizes a long list inside a scroll container.

Browser-only demo

This demo starts after the page mounts in the browser.
import { useMemo, useRef } from 'preact/hooks'
import { useVirtualList } from '@kamod-ch/hooks'

export default function UseVirtualListDemo() {
  const list = useMemo(() => Array.from({ length: 200 }, (_, index) => 'Row ' + (index + 1)), [])
  const containerRef = useRef<HTMLDivElement>(null)
  const wrapperRef = useRef<HTMLDivElement>(null)
  const [visible, scrollTo] = useVirtualList(list, { containerTarget: containerRef, wrapperTarget: wrapperRef, itemHeight: 36, overscan: 4 })

  return (
    <div>
      <p><strong>Total items:</strong> {list.length} · <strong>Rendered items:</strong> {visible.length}</p>
      <button type="button" onClick={() => scrollTo(120)}>Scroll to item 121</button>
      <div ref={containerRef} class="demo-scroll-box" style={{ height: '220px' }}>
        <div ref={wrapperRef}>
          {visible.map((item) => <div key={item.index} class="demo-virtual-row">{item.data}</div>)}
        </div>
      </div>
    </div>
  )
}

API

TypeScript signature
import type { BasicTarget } from '../utils/domTarget.js';
type ItemHeight<T> = (index: number, data: T) => number;
export interface Options<T> {
    containerTarget: BasicTarget;
    wrapperTarget: BasicTarget;
    itemHeight: number | ItemHeight<T>;
    overscan?: number;
}
declare const useVirtualList: <T = any>(list: T[], options: Options<T>) => readonly [{
    index: number;
    data: T;
}[], (this: unknown, index: number) => void];
export default useVirtualList;
/

SSR considerations

This hook touches browser APIs. Render it after mount or guard it with BrowserOnly in SSR and static builds.

Browser compatibility

Requires the corresponding browser API to exist in the current environment.