Skip to main content

Design system components

VirtualList

Fixed-height windowed list with overscan and explicit assistive-technology position metadata.

Status: beta. Group: data-display. Markdown version: /design-system/components/virtual-list.md

When to use

Use VirtualList for long, fixed-height collections when rendering every item would be wasteful. Keep item keys stable and row height accurate.

When not to use

  • Do not use it for short collections.
  • Do not use it for variable-height rows.
  • Do not use it when browser find-in-page must search every item.
  • Do not use VirtualList for variable-height rows or full-page text search.

Look-alikes

The contract names no look-alike with a deciding condition.

Props

VirtualList props
PropTypeDefaultDescriptionRequired
itemsItem[]noneComplete item collection.Yes
itemHeightnumbernoneFixed item height in pixels.Yes
heightnumbernoneVisible viewport height in pixels.Yes
getItemKey(item: Item, index: number) => React.KeynoneStable item key.Yes
getItemProps(item: Item, index: number) => VirtualListItemContentnoneMaps an item to its VirtualListItem chrome (label via children, plus optional icon, meta, trailingIcon, selected, tone). VirtualList injects the position (posInSet/setSize) and windowing style.Yes
aria-labelstringnoneAccessible list name.Yes
overscannumber3Extra rows rendered before and after the viewport.No
initialScrollOffsetnumber0Initial scroll offset in pixels.No
onRangeChange(range: VirtualListRange) => voidnoneReceives the rendered index range.No
classNamestringnoneNo description in the contract.No

Variants

No variant dimensions and no props with a fixed set of values.

Invalid combinations

The contract records no invalid combinations.

Keyboard

VirtualList keyboard behaviour
KeyBehaviour
PageUpNamed in the contract without a description.
PageDownNamed in the contract without a description.
HomeMoves to the first item. (standard)
EndMoves to the last item. (standard)

Rows marked (standard) name a key the contract lists without a description; the behaviour shown is the usual one for that key.

Rules

Every item under When not to use is a MUST NOT. MUST and SHOULD follow RFC 2119.

VirtualList rules
LevelRuleHow it is checked
MUSTARIA: Viewport uses role=list and an accessible name.Not yet verified: no evidence record. WCAG 4.1.2.
MUSTARIA: Rendered rows use role=listitem.Not yet verified: no evidence record. WCAG 4.1.2.
MUSTARIA: Rows expose aria-posinset and aria-setsize.Not yet verified: no evidence record. WCAG 4.1.2.
MUSTRequired stories produce no axe violations at the configured severity.Automated by npm run test:stories:matrix:ci. WCAG 2.5.8.
MUSTThe accessibility tree (role, name, state) matches the committed snapshot for every required story.Automated by npm run test:stories:matrix:ci. WCAG 1.3.1, 4.1.2.
MUSTThe component remains legible and operable under a real browser forced-colors: active pass.Automated by npm run test:stories:hc.
MUSTEvery documented keyboard interaction works as specified.Not yet verified: no evidence record. WCAG 2.1.1, 2.1.2.
MUSTA human completed an end-to-end accessibility review of this component.Manual review, last on 2026-07-26.
SHOULDMeasure and provide the exact fixed row height used by rendered items.Not stated in the contract.
SHOULDUse stable item keys that survive filtering, sorting, and refreshes.Not stated in the contract.
SHOULDKeep overscan small while preventing blank edges during normal scrolling.Not stated in the contract.
SHOULDUse range changes for prefetching without coupling them to visual state.Not stated in the contract.
SHOULD NOTDo not virtualize a short collection that renders cheaply without it.Not stated in the contract.

Install and import

  • Install: npm install @digitaltableteur/react (version 0.9.1, restricted access on npm).
  • Import: import { VirtualList } from "@digitaltableteur/react";
  • Entry point: @digitaltableteur/react/content exports it too.
  • Styles: import @digitaltableteur/react/style.css once at the app boundary.