svelte-virtual-list
svelte-virtual-list copied to clipboard
Support multiple items per row
It would be great if this also could support multiple items per row, to enable grid-like views.
Would you be interested in expanding VirtualList to take an itemsPerRow parameter?
<VirtualList items={items} itemsPerRow={3} />
Any progress on this? Maybe not from Rich.
I found it was quite simple to create a regular CSS grid and simply place an IntersectionObserver
below it that adds additional items to the grid every time it intersects the viewport. See here for a working implementation: https://studenten-bilden-schueler.de/blog (source). Would look something like this:
<script>
import PostPreview from './components/PostPreview.svelte'
import IntersectionObserver from './components/IntersectionObserver.svelte'
export let posts
let activeTag
let nVisible = 9
const onIntersect = () => (nVisible += 6)
$: visiblePosts = posts.slice(0, nVisible)
</script>
<ul>
{#each visiblePosts as post (post.slug)}
<PostPreview {post} />
{/each}
</ul>
<IntersectionObserver on:intersect={onIntersect} top={400} />
<style>
ul {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(18em, 1fr));
gap: 1em;
}
</style>
@boutros and @japgun I came up with a little solution whereby I output 6 items from my array in each virtual list row and control those with css grid. Looks a bit mad i'll admit but does work and is performant. If you want more than 6 on a virtual list row container then change everywhere it says 6
<VirtualList height="100vh" {items} let:item>
<div class="row">
<!-- loop for items in each row, that references 0..5, then 6..11 etc -->
{#each Array(6) as _, i}
{#if data[item * 6 + i]}
{data[item * 6 + i].name}
{/if}
{/each}
</div>
</VirtualList>
<script>
import VirtualList from '@sveltejs/svelte-virtual-list'
// Array of data to display in virtual list
export let data
// New array that contains numbers 1..n
// Dividing the data array length by 6 as there are 6 items per row
let items = [...Array(Math.ceil(data.length / 6)).keys()]
</script>
<style lang="scss">
.row {
display: grid;
gap: 1rem;
/* change the number in the repeat to control items per line */
grid-template-columns: repeat(3, minmax(0, 1fr));
}
</style>
How would you possibly pass a component here? the below doesn't work
<VirtualList height="100vh" {items} bind:start bind:end let:item>
<ItemCard product={item}/>
</VirtualList>
@blazzjosh if you are implementing my example you'll need to wrap your ItemCard like so:
<VirtualList height="100vh" {items} let:item>
<div class="row">
<!-- loop for items in each row, that references 0..5, then 6..11 etc -->
{#each Array(6) as _, i}
{#if data[item * 6 + i]}
<ItemCard product={data[item * 6 + i]}/>
{/if}
{/each}
</div>
</VirtualList>
<script>
import VirtualList from '@sveltejs/svelte-virtual-list'
import ItemCard from '../components/ItemCard.svelte'
// Array of data to display in virtual list
export let data
// New array that contains numbers 1..n
// Dividing the data array length by 6 as there are 6 items per row
let items = [...Array(Math.ceil(data.length / 6)).keys()]
</script>
<style lang="scss">
.row {
display: grid;
gap: 1rem;
/* change the number in the repeat to control items per line */
grid-template-columns: repeat(3, minmax(0, 1fr));
}
</style>