af-utils / virtual

Headless API Reference

Headless API is the core of the library and it provides maximum flexibility. You can work with it directly or delegate rendering to List or Table.


# npm
npm i -S @af-utils/react-virtual-headless use-sync-external-store

# yarn
yarn add @af-utils/react-virtual-headless use-sync-external-store


Core react hook. Used to get scroller model instance synchronized with props. This instance will persist for the full lifetime of the component.

const model = useVirtual({

itemCount: number

Quantity of items. Defaults to 0.

estimatedItemSize: number

Best-guess item size. Defaults to 40.

overscanCount: number

Minimum amount of items to load behind/ahead(depends on scroll direction) of the current visible range. Defaults to 3. Example.

horizontal: boolean

Determines, whether scrollTop/offsetHeight or scrollLeft/offsetWidth are used in calculations. Defaults to false.

estimatedWidgetSize: number

Widget size to use before ResizeObserver measurements are ready. Used mainly for server-side rendering. Defaults to 200.


Scroller model instance with following public props:

from: number

Items range start.

to: number

Items range end.

scrollSize: number

Sum of all item sizes.

el: (index: number, element: Element) => void

Start observing size of element at index. Observing is finished if element is falsy.

setStickyHeader: (element: Element) => void

Start observing size of sticky header element. Observing is finished if element is falsy.

setStickyFooter: (element: Element) => void

Start observing size of sticky footer element. Observing is finished if element is falsy.

getIndex: Function(offset: number) => number

Get element index pixel offset.

getOffset: Function(index: number) => number

Get pixel offset for element index.

getSize: Function(index: number) => number

Get cached size for element at index.

visibleFrom: Getter() => number

Get snapshot of current scroll position. For example 5.3 stands for element at index 5 + 30% of its height. Used to remember scroll position before prepending elements. Example.

scrollTo: (index: Double, smooth: Boolean ) => void

Scroll to element at certain index. For example 3.6 will scroll to element at index 3 plus 60% of its height.

setScroller: (el: HTMLElement | Window) => void

Pass scrollable element to model. Must be attached to outermost element with overflow: auto.

setContainer: Function(el: Element) => void

Should be used ONLY if scroller is located outside (for example window scroll). Needed for proper top/left offset calculation.

set: (params: Object) => void

Manually updates model params. Should be used ONLY with useVirtualModel. Accepts all params of useVirtual except estimatedWidgetSize.


Low-level react hook, used by useVirtual internally. Accepts same params, but without synchronization with props. Usage example. Difference and interconnection between these 2 hooks:

import { useLayoutEffect } from "react";
import useVirtualModel from "../useVirtualModel";

const useVirtual = params => {
    const model = useVirtualModel(params);

    useLayoutEffect(() => model.set(params));

    return model;


mapVisibleRange(model, callback, provideOffset);

model: Model

Required. Return value of useVirtual.

callback: Function( index, offset ) => ReactElement

Required. Function called for each visible element index.

countOffset: boolean

Should provide offset to callback or not. Needed for lists, where each item is absolutely positioned. Defaults to: false.



Numeric event constants

Scroller model has build-in event emitter. All possible events are exported.


    Visible range (model.from or changed. Used to make load on demand.


    Sum of item sizes changed.


    At least one item size changed. Used, when all items are position: absolute and are not automatically realigned when siblinbgs are resized.

  • EVT_ALL(array of events above)


Called, when at least one of passed events is triggered.

useSubscription(model, events, callback);

model: Model

Required. Return value of useVirtual.

events: number[]

Required. Array of events to subscribe

callback: () => void

Gets called when at least one of events gets triggered. In case you do not want to subscribe - pass null.


Normally setScroller should be used to pass scroller to model. Use this if scroller is located outside (window scroll).

useScroller(model, window);


Rerendered, when at least one of passed events is triggered. Example.

<Subscription model={model} events={events}>
    {() => {}}

model: Model

Required. Return value of useVirtual.

children: () => ReactElement

Required. Render prop.

events: number[]

Required. Defaults to: EVT_ALL