Virtual Scroll

High-performance scrolling list that only renders the visible range for large datasets. Not intended for variable-height content that cannot be measured reliably.

Basic Usage

Use virtual scroll for long, fixed-height lists. Rendering only visible rows improves performance with large datasets.

<ds-virtual-scroll item-height="48" buffer="5" label="Basic usage items"></ds-virtual-scroll>

<script>
  const list = document.querySelector('ds-virtual-scroll');
  list.setItems([{ label: 'Item 1' }, { label: 'Item 2' }]);
</script>

Initial Value

Start with an initial scroll offset to restore previous list position.

<ds-virtual-scroll scroll-offset="240" label="Restored position items"></ds-virtual-scroll>

Variants/Formats

Adjust item density and overscan behavior using item height and buffer.

Standard Density

Compact Density

Larger Rows

<ds-virtual-scroll item-height="40" buffer="4" label="Compact density items"></ds-virtual-scroll>
<ds-virtual-scroll item-height="48" buffer="5" label="Standard density items"></ds-virtual-scroll>
<ds-virtual-scroll item-height="56" buffer="3" label="Larger row items"></ds-virtual-scroll>

States

Common states for empty and populated datasets.

Populated List

Empty List

const emptyList = document.querySelector('#state-empty');
emptyList.setItems([]);

Interactive Example

Control virtual scrolling programmatically and observe emitted metrics.

Top Middle End
Start Index
0
End Index
0
Viewport Rows
0
Rendered Rows
0
const list = document.querySelector('#interactive-demo');

list.addEventListener('scroll-change', (event) => {
  console.log(event.detail.startIdx, event.detail.endIdx);
});

list.scrollToIndex(500, 'center');
list.focusItem(250);

API Reference

Attributes

Attribute Type Default Description
item-height number 48 Fixed row height in pixels
buffer number 5 Rows rendered above and below visible viewport
scroll-offset number 0 Initial or programmatic scrollTop offset in pixels
label string Items Accessible name for the role="listbox" container. Always set a real one describing the list's content (e.g. "Search results") rather than relying on the generic fallback.

Events

Event Detail Description
scroll-change { startIdx, endIdx, scrollTop, visibleCount, viewportCount, totalCount } Emitted when scroll position or visible range changes

Methods

Method Description
setItems(items) Sets list items and resets scroll position
getVisibleItems() Returns currently rendered item data slice
scrollToIndex(index, align) Scrolls to target row with start, center, or end alignment
focusItem(index) Scrolls to and focuses an item

CSS Parts

Part Description
(none) This component currently does not expose shadow parts

CSS Custom Properties

Property Description
--ds-virtual-scroll-item-height Default row height token mapping (defaults to --ds-size-control-lg)
--ds-virtual-scroll-focus-width Focus ring width on virtual rows
--ds-virtual-scroll-focus-color Focus ring color on virtual rows

Accessibility

Keyboard Interaction

Key Behavior
Arrow Down Moves focus to the next row and scrolls it into view
Arrow Up Moves focus to the previous row and scrolls it into view
Home Moves focus to the first row
End Moves focus to the last row
Page Down Moves focus down by approximately one viewport of rows
Page Up Moves focus up by approximately one viewport of rows

Semantic Structure

  • The rendered rows container exposes role="listbox" semantics for assistive technologies, named by the label attribute (falls back to "Items" when unset — always set a real one).
  • Each rendered row carries role="option", the child role role="listbox" requires.
  • Virtualized rows are keyboard-focusable so screen reader and keyboard users can traverse visible content.
  • Focused rows include a visible focus treatment using MD3 focus ring tokens.
  • Native pointer, wheel, and touch scrolling behavior is preserved.

Usage Guidelines

  • When to use: Use virtual scroll for long, fixed-height lists where rendering all rows at once would hurt performance.
  • When not to use: Avoid virtual scroll for variable-height or auto-wrapping rows that cannot be measured consistently.
  • Composition: Keep item-height accurate, tune buffer to balance smoothness and render cost, and use scroll-offset for state restoration.
  • Common mistakes: Mixing highly dynamic row heights or embedding expensive per-row layout work can negate virtualization benefits.