TanStack / virtual

🤖 Headless UI for Virtualizing Large Element Lists in JS/TS, React, Solid, Vue and Svelte
https://tanstack.com/virtual
MIT License
5.55k stars 303 forks source link

Prop 'gap' doesn't work with the dynamic implementation #793

Closed carledwardfp closed 3 months ago

carledwardfp commented 3 months ago

Describe the bug

The 'gap' doesn't work with the dynamic implementation of tanstack virtual. Adding gap does not actually add gap on the items. But the height changed and there's a big space at the bottom (check codesandbox link)

Your minimal, reproducible example

https://codesandbox.io/p/devbox/silly-carlos-7p3tzg?file=%2Fsrc%2Fmain.tsx%3A26%2C13

Steps to reproduce

  1. Create a virtualized component
  2. Add the gap prop and check

Expected behavior

There should be a gap between the virtualized items

How often does this bug happen?

Every time

Screenshots or Videos

No response

Platform

macOS, Chrome 127.0.6533.100

tanstack-virtual version

v3.8.6

TypeScript version

5.2.2

Additional context

No response

Terms & Code of Conduct

piecyk commented 3 months ago

Yes, as in the example above it will not work, list is absolute positioning to control where visible items are rendered, so the whole block is moved. To make the gap work, we need to use relative positioning on items like

 <div
  ref={parentRef}
  style={{
    height: `200px`,
    width: `400px`,
    overflow: 'auto',
  }}
>
  <div
    style={{
      height: `${rowVirtualizer.getTotalSize()}px`,
      width: '100%',
      position: 'relative',
    }}
  >
    {rowVirtualizer.getVirtualItems().map((virtualRow) => (
      <div
        key={virtualRow.key}
        style={{
          position: 'absolute',
          top: 0,
          left: 0,
          width: '100%',
          height: `${virtualRow.size}px`,
          transform: `translateY(${virtualRow.start}px)`,
        }}
      >
        Row {virtualRow.index}
      </div>
    ))}
  </div>
</div>