Vue Example: Scroll Padding

vue
<template>
  <div>
    <div>
      <button @click="rowVirtualizer.scrollToIndex(40)">
        Scroll to index 40
      </button>
      <button @click="rowVirtualizer.scrollToIndex(20)">
        Then scroll to index 20
      </button>
    </div>

    <br />
    <br />

    <div
      ref="parentRef"
      class="List"
      style="height: 200px; width: 400px; overflow: auto"
    >
      <table :style="{ height: `${totalSize}px`, width: '100%' }">
        <thead ref="theadRef">
          <tr>
            <th>Index</th>
            <th>Key</th>
          </tr>
        </thead>
        <tbody>
          <tr
            v-for="virtualRow in virtualRows"
            :key="virtualRow.index"
            :class="virtualRow.index % 2 ? 'ListItemOdd' : 'ListItemEven'"
            :style="{
              position: 'absolute',
              top: 0,
              left: 0,
              width: '100%',
              height: `${virtualRow.size}px`,
              transform: `translateY(${virtualRow.start}px)`,
            }"
          >
            <td>#{{ virtualRow.index }}</td>
            <td>{{ virtualRow.key }}</td>
          </tr>
        </tbody>
      </table>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, computed } from 'vue'
import { useElementSize } from '@vueuse/core'
import { useVirtualizer } from '@tanstack/vue-virtual'

const parentRef = ref<HTMLElement | null>(null)

const theadRef = ref<HTMLElement | null>(null)

const { height } = useElementSize(theadRef)

const rowVirtualizerOptions = computed(() => {
  return {
    count: 10000,
    getScrollElement: () => parentRef.value,
    estimateSize: () => 35,
    overscan: 5,
    paddingStart: height.value ?? 0,
    scrollPaddingStart: height.value ?? 0,
  }
})

const rowVirtualizer = useVirtualizer(rowVirtualizerOptions)

const virtualRows = computed(() => rowVirtualizer.value.getVirtualItems())

const totalSize = computed(() => rowVirtualizer.value.getTotalSize())
</script>
<template>
  <div>
    <div>
      <button @click="rowVirtualizer.scrollToIndex(40)">
        Scroll to index 40
      </button>
      <button @click="rowVirtualizer.scrollToIndex(20)">
        Then scroll to index 20
      </button>
    </div>

    <br />
    <br />

    <div
      ref="parentRef"
      class="List"
      style="height: 200px; width: 400px; overflow: auto"
    >
      <table :style="{ height: `${totalSize}px`, width: '100%' }">
        <thead ref="theadRef">
          <tr>
            <th>Index</th>
            <th>Key</th>
          </tr>
        </thead>
        <tbody>
          <tr
            v-for="virtualRow in virtualRows"
            :key="virtualRow.index"
            :class="virtualRow.index % 2 ? 'ListItemOdd' : 'ListItemEven'"
            :style="{
              position: 'absolute',
              top: 0,
              left: 0,
              width: '100%',
              height: `${virtualRow.size}px`,
              transform: `translateY(${virtualRow.start}px)`,
            }"
          >
            <td>#{{ virtualRow.index }}</td>
            <td>{{ virtualRow.key }}</td>
          </tr>
        </tbody>
      </table>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, computed } from 'vue'
import { useElementSize } from '@vueuse/core'
import { useVirtualizer } from '@tanstack/vue-virtual'

const parentRef = ref<HTMLElement | null>(null)

const theadRef = ref<HTMLElement | null>(null)

const { height } = useElementSize(theadRef)

const rowVirtualizerOptions = computed(() => {
  return {
    count: 10000,
    getScrollElement: () => parentRef.value,
    estimateSize: () => 35,
    overscan: 5,
    paddingStart: height.value ?? 0,
    scrollPaddingStart: height.value ?? 0,
  }
})

const rowVirtualizer = useVirtualizer(rowVirtualizerOptions)

const virtualRows = computed(() => rowVirtualizer.value.getVirtualItems())

const totalSize = computed(() => rowVirtualizer.value.getTotalSize())
</script>
Subscribe to Bytes

Your weekly dose of JavaScript news. Delivered every Monday to over 100,000 devs, for free.

Bytes

No spam. Unsubscribe at any time.

Subscribe to Bytes

Your weekly dose of JavaScript news. Delivered every Monday to over 100,000 devs, for free.

Bytes

No spam. Unsubscribe at any time.