Quartz Headless docs/Virtual Scroll

Search documentation

Type to search the documentation.

Core

Virtual Scroll

Efficiently render massive lists by only mounting DOM nodes that are visible in the viewport. Fully headless — you control the markup and styling.

At a glance

  • Fixed Size — Optimized for uniform item heights
  • Buffer — Prerender items outside viewport
  • Scroll To Index — Programmatic navigation
  • Resize Aware — Recalculates on viewport resize

Live examples

Loading demo…

Code

10 000 Items

<div
  class="viewport"
  qzVirtualScroll
  [items]="users()"
  [itemSize]="56"
  [buffer]="4"
  #vs="qzVirtualScroll"
>
  <div class="content" [style.height.px]="vs.contentHeight()">
    @for (row of vs.visibleItems(); track row.index) {
    <div class="row" [style.top.px]="row.offset">
      <strong>#{{ row.index + 1 }}</strong>
      <span>{{ row.item.name }}</span>
      <small>{{ row.item.email }}</small>
    </div>
    }
  </div>
</div>

What The Directive Exposes

<!-- Template reference -->
<div qzVirtualScroll [items]="items" [itemSize]="50" #vs="qzVirtualScroll">...</div>

<!-- Scroll to index -->
<button (click)="vs.scrollToIndex(0)">Top</button>
<button (click)="vs.scrollToIndex(5000)">Middle</button>
<button (click)="vs.scrollToIndex(vs.count() - 1)">Bottom</button>

<!-- Read signals -->
<p>Rendered: {{ vs.visibleItems().length }} / {{ vs.count() }}</p>
<p>Range: {{ vs.startIndex() + 1 }} - {{ vs.endIndex() + 1 }}</p>
<p>Scroll height: {{ vs.contentHeight() }}px</p>