Virtual list

Windows large fixed-height collections while preserving focused rows.

Record 1
Record 2
Record 3
Record 4
Record 5
Record 6
Record 7
Record 8
Record 9
Record 10
Record 11
Record 12
Record 13
Record 14
Record 1
Record 2
Record 3
Record 4
Record 5
Record 6
Record 7
Record 8
Record 9
Record 10
Record 11
Record 12
Record 13
Record 14

Use it for

  • Large collections where fixed-height rows are an acceptable constraint.

Not for

  • Short lists or variable-height content without a fixed row contract.

Three ways in. They share one source, so the pixels match whichever you pick.

1. Import the package

npm install @noorddev/vlak-react

// once, next to your app's root
import "@noorddev/vlak-react/css";

import { VirtualList } from "@noorddev/vlak-react";

Precompiled React and one stylesheet. No compiler to configure. Per-component imports work too: @noorddev/vlak-react/components/virtual-list.

2. Vendor the source

npx @noorddev/vlak-cli add virtual-list

The StyleX leaf lands in components/vlak/, for your own compiler to own. See StyleX.

3. Through shadcn

npx shadcn add https://vlak.dev/r/virtual-list.json

The same registry item, installed by shadcn's CLI.

CSS only

<link rel="stylesheet" href="node_modules/@noorddev/vlak/css/vlak.css" />

No React. Link vlak.css and use the markup and classes below.

import { VirtualList } from "@noorddev/vlak-react";

<VirtualList label="Records" height={264} items={Array.from({ length: 200 }, (_, index) => ({ id: String(index), label: `Record ${index + 1}` }))} />

VirtualList

Fixed-height windowing with a retained focused row and keyboard navigation.

PropTypeDefaultDescription
itemsrequiredVirtualItem[]
labelrequiredstring
rowHeightnumber44Fixed row height, at least 44px.
heightnumber352
overscannumber4
emptyLabelstring"No items"

Also accepts HTMLAttributes<HTMLDivElement>.

KeysDoes
Tab, Arrow up/down, Home, EndA row enters the Tab sequence; arrows and Home/End scroll and focus rows. Nested controls keep their own keys.
<div class="rs-virtual-list" role="list" aria-label="Records" style="height:264px"><div class="rs-virtual-list-canvas" role="none" style="height:44px"><div class="rs-virtual-list-item" role="listitem" tabindex="0" aria-posinset="1" aria-setsize="1" style="height:44px">Record 1</div></div></div>
.rs-virtual-list.rs-virtual-list-canvas.rs-virtual-list-item.rs-virtual-list-empty