petyosi / react-virtuoso

The most powerful virtual list component for React
https://virtuoso.dev
MIT License
5.16k stars 299 forks source link

[BUG] `VirtuosoGrid` doesn’t handle CSS grid with `auto-fit` columns well #1023

Closed iamakulov closed 8 months ago

iamakulov commented 8 months ago

Describe the bug

Take the following CSS layout:

.grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
}

.item {
  /* item styles */
}

With this layout, the size of each .item will be between 200px and 100%, depending on how wide the grid is and how many elements there are in the grid. E.g. if the grid is 900px and has 5 items in it, this is how it will look on the page:

---------------------------------
| 225px | 225px | 225px | 225px |
| 225px |
---------------------------------

This layout does not work well with Virtuoso. If you wrap this layout with Virtuoso:

<VirtuosoGrid
  totalCount={9999}
  listClassName="grid"
  itemContent={(index) => <div className="item">{/* Content that makes .item taller than the viewport */</div>}
/>

it will try to estimate the size of each item by rendering only the first item. However, the size of each item depends on how many items there are! So if you only render one, it will fill the full grid:

---------------------------------
|              900px            |
---------------------------------

making Virtuoso render the grid incorrectly. And in case when the item is really tall (taller than the viewport), it will also stay incorrect – until the user scrolls down and Virtuoso tries to append more items to the grid.

Reproduction Here’s a demo: Stackblitz

Notice how when you load the live demo, the page renders a single item – until you scroll down, when Virtuoso tries to add another item into the grid, and the layout becomes correct:

https://github.com/petyosi/react-virtuoso/assets/2953267/67a8241b-bfbd-481f-9383-789bcd7835df

Furthermore, if you resize the window down, the CSS grid will go down to a single item per row – and then Virtuoso will keep it at a single item per row when you resize the window back up:

https://github.com/petyosi/react-virtuoso/assets/2953267/3bcf7173-8c2f-4897-aa49-a718dcb61c78

Expected behavior The grid layout should look in the same way it would have looked without Virtuoso – i.e.:

Desktop (please complete the following information):

Additional context A possible workaround for this is using the initialItemCount prop – however, this only fixes the initial render, not the resizing scenario. Another possible workaround for this might’ve been increaseViewportBy (?) – but it’s not supported on grids, only on lists.

petyosi commented 8 months ago

Yep, that's not supported.

iamakulov commented 8 months ago

Thank you. Would you consider exposing increaseViewportBy on grids as a workaround for this issue? I realize this becomes more of a feature request at this point 😅, but I’m also happy to PR it if you’re accepting external PRs, and adding this prop is mostly about prop drilling and not about solving some unsolved challenges.

petyosi commented 8 months ago

Of course, PR is welcome.