Virtual Scroller

The Virtual Scroller component provides efficient rendering of large lists by only rendering visible items and using virtual scrolling techniques. It automatically calculates which items should be visible based on scroll position and item heights, dramatically improving performance for large datasets. Perfect for displaying thousands of items without performance degradation.

Basic virtual scrolling

The Virtual Scroller only renders items that are currently visible in the viewport, making it ideal for large lists. Provide an array of items and use the item slot to render each item.

Source code
<template>
  <IkVirtualScroller
    :items="items"
    :item_height="50"
    style="height: 400px; border: 1px solid var(--border-neutral-regular-default); border-radius: 4px;"
  >
    <template #item="{ item }">
      <div style="padding: 12px; border-bottom: 1px solid var(--border-neutral-regular-default);">
        {{ item.name }} - {{ item.email }}
      </div>
    </template>
  </IkVirtualScroller>
</template>
<script setup>
import { IkVirtualScroller } from '@ikol/ui-kit/components/IkVirtualScroller';
import { ref } from 'vue';

const items = ref(Array.from({ length: 1000 }, (_, i) => ({
  id: i + 1,
  name: `User ${i + 1}`,
  email: `user${i + 1}@example.com`
})));
</script>

Dynamic item heights

When items have varying heights, the Virtual Scroller automatically measures each item and adjusts the scroll calculations. You can provide a function to estimate item heights.

Item 1

This is a longer description that takes up more vertical space to demonstrate dynamic height calculation.

Category 1 • Updated 0 days ago

Item 2

Short description.

Category 2 • Updated 1 days ago

Item 3

Short description.

Category 3 • Updated 2 days ago

Item 4

This is a longer description that takes up more vertical space to demonstrate dynamic height calculation.

Category 4 • Updated 3 days ago

Item 5

Short description.

Category 5 • Updated 4 days ago

Item 6

Short description.

Category 1 • Updated 5 days ago

Item 7

This is a longer description that takes up more vertical space to demonstrate dynamic height calculation.

Category 2 • Updated 6 days ago

Item 8

Short description.

Category 3 • Updated 7 days ago

Item 9

Short description.

Category 4 • Updated 8 days ago

Item 10

This is a longer description that takes up more vertical space to demonstrate dynamic height calculation.

Category 5 • Updated 9 days ago

Item 11

Short description.

Category 1 • Updated 0 days ago

Item 12

Short description.

Category 2 • Updated 1 days ago

Item 13

This is a longer description that takes up more vertical space to demonstrate dynamic height calculation.

Category 3 • Updated 2 days ago

Item 14

Short description.

Category 4 • Updated 3 days ago

Item 15

Short description.

Category 5 • Updated 4 days ago

Item 16

This is a longer description that takes up more vertical space to demonstrate dynamic height calculation.

Category 1 • Updated 5 days ago

Item 17

Short description.

Category 2 • Updated 6 days ago

Item 18

Short description.

Category 3 • Updated 7 days ago

Item 19

This is a longer description that takes up more vertical space to demonstrate dynamic height calculation.

Category 4 • Updated 8 days ago

Item 20

Short description.

Category 5 • Updated 9 days ago

Item 21

Short description.

Category 1 • Updated 0 days ago

Item 22

This is a longer description that takes up more vertical space to demonstrate dynamic height calculation.

Category 2 • Updated 1 days ago

Item 23

Short description.

Category 3 • Updated 2 days ago

Item 24

Short description.

Category 4 • Updated 3 days ago

Item 25

This is a longer description that takes up more vertical space to demonstrate dynamic height calculation.

Category 5 • Updated 4 days ago
Source code
<template>
  <IkVirtualScroller
    :items="items"
    :item_height="getItemHeight"
    style="height: 400px; border: 1px solid var(--border-neutral-regular-default); border-radius: 4px;"
  >
    <template #item="{ item }">
      <div style="padding: 16px; border-bottom: 1px solid var(--border-neutral-regular-default);">
        <h4 style="margin: 0 0 8px 0;">{{ item.title }}</h4>
        <p style="margin: 0; color: var(--text-neutral-weak-default);">
          {{ item.description }}
        </p>
        <div style="margin-top: 8px; font-size: 12px; color: var(--text-neutral-weak-default);">
          {{ item.meta }}
        </div>
      </div>
    </template>
  </IkVirtualScroller>
</template>
<script setup>
import { IkVirtualScroller } from '@ikol/ui-kit/components/IkVirtualScroller';
import { ref } from 'vue';

const items = ref(Array.from({ length: 500 }, (_, i) => ({
  id: i + 1,
  title: `Item ${i + 1}`,
  description: i % 3 === 0 
    ? 'This is a longer description that takes up more vertical space to demonstrate dynamic height calculation.'
    : 'Short description.',
  meta: `Category ${i % 5 + 1} • Updated ${i % 10} days ago`
})));

function getItemHeight(item) {
  // Estimate height based on content
  return item.description.length > 50 ? 120 : 80;
}
</script>

Large dataset performance

The Virtual Scroller handles extremely large datasets efficiently. Even with tens of thousands of items, only the visible items are rendered, maintaining smooth scrolling performance.

Rendering 10000 items (only visible items are in the DOM)

1
Item #1
Description for item 1
2
Item #2
Description for item 2
3
Item #3
Description for item 3
4
Item #4
Description for item 4
5
Item #5
Description for item 5
6
Item #6
Description for item 6
7
Item #7
Description for item 7
8
Item #8
Description for item 8
9
Item #9
Description for item 9
10
Item #10
Description for item 10
11
Item #11
Description for item 11
12
Item #12
Description for item 12
13
Item #13
Description for item 13
14
Item #14
Description for item 14
15
Item #15
Description for item 15
16
Item #16
Description for item 16
17
Item #17
Description for item 17
18
Item #18
Description for item 18
19
Item #19
Description for item 19
20
Item #20
Description for item 20
21
Item #21
Description for item 21
22
Item #22
Description for item 22
23
Item #23
Description for item 23
24
Item #24
Description for item 24
25
Item #25
Description for item 25
Source code
<template>
  <div>
    <p style="margin-bottom: 8px;">
      Rendering {{ items.length }} items (only visible items are in the DOM)
    </p>
    <IkVirtualScroller
      :items="items"
      :item_height="40"
      style="height: 400px; border: 1px solid var(--border-neutral-regular-default); border-radius: 4px;"
    >
      <template #item="{ item }">
        <div style="padding: 10px; border-bottom: 1px solid var(--border-neutral-regular-default); display: flex; align-items: center; gap: 12px;">
          <div style="width: 32px; height: 32px; border-radius: 50%; background: var(--background-neutral-weak-default); display: flex; align-items: center; justify-content: center;">
            {{ item.id % 100 }}
          </div>
          <div>
            <div style="font-weight: 500;">Item #{{ item.id }}</div>
            <div style="font-size: 12px; color: var(--text-neutral-weak-default);">Description for item {{ item.id }}</div>
          </div>
        </div>
      </template>
    </IkVirtualScroller>
  </div>
</template>
<script setup>
import { IkVirtualScroller } from '@ikol/ui-kit/components/IkVirtualScroller';
import { ref } from 'vue';

const items = ref(Array.from({ length: 10000 }, (_, i) => ({
  id: i + 1,
  name: `Item ${i + 1}`
})));
</script>

Programmatic scrolling

Use template refs to programmatically scroll to specific items or positions. The component exposes scrollToIndex and scrollTop methods.

Item 1: Item 1
Item 2: Item 2
Item 3: Item 3
Item 4: Item 4
Item 5: Item 5
Item 6: Item 6
Item 7: Item 7
Item 8: Item 8
Item 9: Item 9
Item 10: Item 10
Item 11: Item 11
Item 12: Item 12
Item 13: Item 13
Item 14: Item 14
Item 15: Item 15
Item 16: Item 16
Item 17: Item 17
Item 18: Item 18
Item 19: Item 19
Item 20: Item 20
Item 21: Item 21
Item 22: Item 22
Item 23: Item 23
Item 24: Item 24
Item 25: Item 25
Source code
<template>
  <div>
    <div style="display: flex; gap: 8px; margin-bottom: 16px;">
      <IkButton @click="scrollToItem(100)" size="sm">Scroll to Item 100</IkButton>
      <IkButton @click="scrollToItem(500)" size="sm">Scroll to Item 500</IkButton>
      <IkButton @click="scrollToItem(999)" size="sm">Scroll to Item 999</IkButton>
      <IkButton @click="scrollToTop" size="sm">Scroll to Top</IkButton>
    </div>
    <IkVirtualScroller
      ref="scrollerRef"
      :items="items"
      :item_height="50"
      style="height: 400px; border: 1px solid var(--border-neutral-regular-default); border-radius: 4px;"
    >
      <template #item="{ item }">
        <div style="padding: 12px; border-bottom: 1px solid var(--border-neutral-regular-default);">
          Item {{ item.id }}: {{ item.name }}
        </div>
      </template>
    </IkVirtualScroller>
  </div>
</template>
<script setup>
import { IkVirtualScroller } from '@ikol/ui-kit/components/IkVirtualScroller';
import { IkButton } from '@ikol/ui-kit/components/IkButton';
import { ref } from 'vue';

const scrollerRef = ref();
const items = ref(Array.from({ length: 1000 }, (_, i) => ({
  id: i + 1,
  name: `Item ${i + 1}`
})));

function scrollToItem(index) {
  scrollerRef.value?.scrollToIndex(index);
}

function scrollToTop() {
  scrollerRef.value?.scrollTop(0);
}
</script>
Image
IK UI
© 2025 IK UI. All rights reserved.