Skip to content

fix(VVirtualScroll): call calculateVisibleItems after updateOffsets#22938

Open
pinichi wants to merge 1 commit into
vuetifyjs:masterfrom
pinichi:fix/22937-virtual-scroll-padding-bottom
Open

fix(VVirtualScroll): call calculateVisibleItems after updateOffsets#22938
pinichi wants to merge 1 commit into
vuetifyjs:masterfrom
pinichi:fix/22937-virtual-scroll-padding-bottom

Conversation

@pinichi

@pinichi pinichi commented Jun 20, 2026

Copy link
Copy Markdown

Description

resolves #22937

When handleItemResize is called (e.g. after an accordion-like collapse), it triggers the debounced updateOffsets() which correctly rebuilds offsets[].

However, calculateVisibleItems() was never called afterwards, leaving paddingBottom stale until the next scroll event — causing the scrollbar to display an incorrect size.

Markup:

<template>
  <div style="max-width: 600px; margin: 0 auto; padding: 16px">
    <div style="margin: 12px 0; line-height: 2">
      <div>50 items × 48px → item #0 collapses to 12px</div>
      <div>Expected paddingBottom after collapse: <b>~300px</b></div>
      <div>
        Actual paddingBottom:
        <b :style="{ color: paddingBottom !== null && paddingBottom > 800 ? 'red' : 'green' }">
          {{ paddingBottom !== null ? paddingBottom + 'px' : '(click Collapse)' }}
        </b>
        <span v-if="paddingBottom !== null && paddingBottom > 800" style="color: red; font-weight: bold">
          ← stale! (bug)
        </span>
        <span v-else-if="paddingBottom !== null" style="color: green"> ✓ correct</span>
      </div>
    </div>

    <div style="display: flex; gap: 8px; margin-bottom: 12px">
      <button @click="collapse" :disabled="collapsed">Collapse item #0</button>
      <button @click="reset">Reset</button>
    </div>

    <div style="margin-bottom: 8px; font-size: 12px; color: #555">
      <div>👉 1. Click "Collapse item #0" — do NOT scroll</div>
      <div>  2. paddingBottom stays ~1200px (bug)</div>
      <div>  3. Scroll slightly → paddingBottom corrects to ~300px</div>
    </div>

    <v-virtual-scroll ref="vsRef" :items="items" height="400">
      <template #default="{ index }">
        <div :style="{ height: index === 0 && collapsed ? '12px' : '48px' }">
          #{{ index }} — {{ index === 0 && collapsed ? '12px (collapsed)' : '48px' }}
        </div>
      </template>
    </v-virtual-scroll>
  </div>
</template>

<script setup>
import { ref } from 'vue'

const items = Array.from({ length: 50 }, (_, i) => i)
const collapsed = ref(false)
const vsRef = ref(null)
const paddingBottom = ref(null)

async function collapse() {
  collapsed.value = true
  await new Promise(resolve => setTimeout(resolve, 500))
  const container = vsRef.value?.$el?.querySelector('.v-virtual-scroll__container')
  paddingBottom.value = parseFloat(container?.style.paddingBottom ?? '0')
}

function reset() {
  collapsed.value = false
  paddingBottom.value = null
}
</script>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug Report][4.0.3] VVirtualScroll: paddingBottom not updated after item height changes (stale until scroll)

1 participant