Skip to content

API

Layout Virtual is split into a framework-agnostic engine and thin framework adapters.

The layout-virtual package contains the core layout classes, DOM renderer, scroll container, event bus, and the vanilla JS/TS component. The React, Vue, and Angular packages wrap the same core layout and renderer contract with framework-specific rendering primitives. That means the virtualization behavior, sizing model, overscan option, CSS class hooks, and event callbacks are intentionally the same across frameworks.

PackageUse
layout-virtualCore engine, public core types, and the vanilla DOM component.
react-layout-virtualReact component wrapper.
vue-layout-virtualVue component wrapper.
angular-layout-virtualAngular component wrapper.

All components render a scrollable container with a viewport and content layer. Items are created from data only for the visible range plus overscan. Item dimensions are measured from real DOM elements, so rows, grids, margins, gaps, and dynamic heights can be handled with normal CSS.

PropTypeDefaultDescription
dataT[]requiredItems to virtualize. Each rendered item receives its original data object and index.
renderItemframework-specificrequired in JS/TS and ReactFunction that renders one item. Vue and Angular use slots/templates instead.
overscanHeightnumber200Extra vertical space, in pixels, rendered outside the visible viewport in the current scroll direction. Higher values reduce blanking during fast scrolling but render more items.
mutationDataMutationoptionalDescribes an insertion or deletion in data so the list can compensate scroll position when item indices shift. Use it when items are inserted or removed before the rendered range, such as reverse infinite scroll.
scrollerRefframework-specific element refoptionalExisting scroll element to render into. If omitted, the component creates its own scroller element.
scrollerClassframework-specific class valueoptionalClass applied to the scroll container.
viewportClassframework-specific class valueoptionalClass applied to the viewport element inside the scroller.
contentLayerClassframework-specific class valueoptionalClass applied to the element that contains rendered items.

DataMutation has the shape { index: number; insertCount?: number; deleteCount?: number }. Pass it with the same data update it describes: for example, after prepending 20 items, pass { index: 0, insertCount: 20 }; after removing one loader item at the top while inserting 20 real items, pass { index: 0, deleteCount: 1, insertCount: 20 }. The index is the position where the data changed, and the counts describe how many items were inserted or deleted there.

The current wrappers initialize the virtual list when the component mounts or when the vanilla function is called. Treat renderItem and overscanHeight as initialization inputs in the current API.

Each framework receives the same item payload:

type ListItemProps<T> = {
data: T;
index: number;
};

Assign the index to the data-index attribute of the item root element. This contract allows the library to track rendered elements.

import LayoutVirtual, { type ListItemProps } from 'layout-virtual';
type Item = { title: string };
function renderItem({ data, index }: ListItemProps<Item>) {
const element = document.createElement('article');
element.dataset.index = String(index);
element.textContent = data.title;
return element;
}
const { container } = LayoutVirtual({ data, overscanHeight: 200, renderItem, scrollerClass: 'lv-scroller' });
document.getElementById('app')!.append(container);

The component creates this structure:

<div class="scrollerClass" data-lv-scroller>
<div></div>
<div class="viewportClass" data-lv-viewport>
<div>
<div></div>
<div class="contentLayerClass" data-lv-content-layer>
<!-- rendered items -->
</div>
<div></div>
</div>
</div>
</div>

Use these classes to define the scroller size, overflow behavior, and item layout. For responsive grids, put grid or flex layout styles on contentLayerClass and item styles on the rendered item root.

Layout Virtual also adds stable data attributes to its main DOM layers:

AttributeElementUse
data-lv-scrollerScroll containerSelect the outer scroll element.
data-lv-viewportViewport containerSelect the inner virtual viewport.
data-lv-content-layerContent layerSelect the element that contains rendered items.

These attributes are intended as stable selectors. They can be used for styling, although class props are preferable for normal CSS customization because they keep styling names under application control. They are also useful when you need a direct DOM reference:

const scroller = document.querySelector('[data-lv-scroller]');
const viewport = document.querySelector('[data-lv-viewport]');
const contentLayer = document.querySelector('[data-lv-content-layer]');
EventCallbackDescription
onAfterItemsRendered(startIndex: number, endIndex: number, items: HTMLCollection) => voidFires after the current visible range has been flushed to the DOM. This is the main event for counters, diagnostics, and observing the rendered range.
onChange() => voidInternal event emitted when core data or renderer setup changes.
onResize(width: number, height: number) => voidLow-level scroll container resize event.
onScroll(position: number, direction: 'down' | 'up', scrollDelta: number) => voidLow-level native scroller event.
onContentScroll(position: number, direction: 'down' | 'up', scrollDelta: number) => voidLow-level virtual content scroll event.

onBeforeItemsLoaded and onBeforeItemsUnloaded are present in the event type map, but the current layout does not emit them yet.

FrameworkscrollerRef typeClass prop typeItem renderer
JS / TSHTMLDivElementstringrenderItem(props) => HTMLElement
ReactReact.RefObject<HTMLElement>stringrenderItem(props) => React.ReactNode
VueRef<HTMLElement>Vue ClassValue#renderItem slot
AngularElementRef<HTMLElement>string | string[] | Set<string> | Record<string, boolean>#renderItem template