Skip to content

CdsVirtualScroll

New in v4.0

Virtual scrolling keeps long lists fast: only the visible rows get into the DOM, not the whole array. Pass the records to items, the markup of a row to the slot, and a list of tens of thousands of positions scrolls as smoothly as a list of ten.

Storybook GitLab
Test coverage: 94% — good coverage
API in specs
16 / 16 props, events, slots and exposed members with a test
Test cases
23 unit · 3 browser
Known bugs
1 pinned by an it.fails test
Code coverage
93.5% lines · 76.9% branches measured in v4.0.0-alpha.13
A11y (axe)
6 recommendations in 7 stories measured in v4.0.0-alpha.11

The dropdowns of CdsSelect and CdsAutocomplete, as well as the CdsTree tree, already virtualize their items — there is no need to wrap them. Render a short list — up to a couple of hundred rows — with the regular CdsList: virtualization will not pay off there.

Variations ​

Fixed height ​

The height prop sets the height of the viewport — the scrolling happens inside it. If all the rows have the same height, set item-height: the component will not measure every row, and the positions and the scrollbar will be exact from the very first render.

Dynamic height ​

Without item-height the component measures the rows automatically — this fits content of variable length: comments, messages, descriptions. The heights get refined as you scroll, so the scrollbar may shift slightly.

Renderless mode ​

The renderless prop removes the own scroll container: the component listens to the scrolling of the nearest scrollable parent and renders the rows without wrappers. The slot additionally receives itemRef — bind it to the root node of the row so that the component knows its height. This is how the list fits into an existing scroll — of a panel or of the whole page. Give the scrollable parent position: relative — the component counts the row positions from it.

Guidelines ​

Scenarios ​

Pass an already filtered array to items: a computed recalculates the records on input, and the component picks the new list up on its own. item-key="id" binds the rows to the records rather than to the positions in the array — so the rows do not get mixed up while filtering.

Jumping through a journal ​

The component exposes the scrollToIndex method — get it through a ref and scroll the list programmatically. The month buttons calculate the index of the first operation of the month; with a fixed item-height the jump lands exactly on the right row.

Selection in a long list ​

The rows outside the screen do not exist in the DOM, so keep the selection state in the data, not in the rows themselves. In the demo the checked ids live in a Set: the checkbox of a row reads it and changes it on click — the selection survives any scrolling.

API ​

CdsVirtualScroll ​

Props

NameTypeDefaultDescription
heightstring | number | undefined—Component height
itemHeightstring | number | undefinednullHeight of a single item in pixels. When omitted, the height is measured automatically.
itemKeySelectItemKeynullKey that identifies an item (a field name, a path or a function). The index is used by default.
itemsreadonly unknown[] | undefined[]Array of the items rendered by the virtual scroll.
maxHeightstring | number | undefined—Maximum component height
maxWidthstring | number | undefined—Maximum component width
minHeightstring | number | undefined—Minimum component height
minWidthstring | number | undefined—Minimum component width
renderlessboolean | undefined—Renderless mode: the component does not create its own scroll container and uses the nearest scrollable parent instead.
widthstring | number | undefined—Component width

Slots

NameTypeDescription
defaultCdsVirtualScrollSlot<any> & { itemRef?: TemplateRef | undefined; }Content of a single list item. In renderless mode it additionally receives itemRef.

Exposed

NameTypeDescription
calculateVisibleItems() => voidRecalculates the window of visible items — needed after their height changes outside the update cycle.
scrollToIndex(index: number) => voidScrolls the list to the item with the given index.

CdsVirtualScrollItem ​

Props

NameTypeDefaultDescription
renderlessboolean | undefined—Renderless mode: the item renders only the slot content, without a wrapper.

Events

NameTypeDescription
update:height[height: number]Tells the virtual list that the height of the item has changed.

Slots

NameTypeDescription
default{ itemRef: TemplateRef; }Content of the item. In renderless mode it receives itemRef to measure the height.