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.
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 thelabelattribute (falls back to "Items" when unset — always set a real one). -
Each rendered row carries
role="option", the child rolerole="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-heightaccurate, tunebufferto balance smoothness and render cost, and usescroll-offsetfor state restoration. - Common mistakes: Mixing highly dynamic row heights or embedding expensive per-row layout work can negate virtualization benefits.