sly-svelte-infinite-scroll
v1.0.1
Published
A performant infinite scroll component for Svelte with bidirectional loading and dynamic item mounting
Maintainers
Readme
Dead simple infinite scroll for Svelte 5 - just add to the end of any list
About • Features • Installation • Usage • Examples
About
A minimal infinite scroll component that you simply add to the end of your list. When it becomes visible, it calls your load function. When that function returns an empty array, it stops. No complex configuration, no managing state - it just works.
Features
- Drop-in Component - Add to the end of any list, no wrapper needed
- Auto-detection - Automatically stops when you return an empty array
- Performance First - Uses IntersectionObserver for efficient scroll detection
- Zero Dependencies - Just Svelte 5, nothing else
Installation
pnpm add sly-svelte-infinite-scrollnpm install sly-svelte-infinite-scrollyarn add sly-svelte-infinite-scrollRequirements
- Svelte 5.0.0 or higher
- Modern browser with IntersectionObserver support
Usage
<script lang="ts">
import { InfiniteScroll } from 'sly-svelte-infinite-scroll';
let items = $state([]);
async function loadMore() {
const response = await fetch('/api/items?offset=' + items.length);
const newItems = await response.json();
items = [...items, ...newItems];
return newItems; // Return empty array to stop
}
</script>
<div class="list">
{#each items as item}
<div>{item.name}</div>
{/each}
<InfiniteScroll onLoadMore={loadMore} />
</div>Technologies
The component leverages modern web APIs and Svelte's latest features for optimal performance:
- Svelte 5 Runes - Using the new reactivity system with
$stateand$propsdocs - IntersectionObserver API - Efficient visibility detection without scroll listeners docs
- TypeScript - Full type safety with generic item types docs
Examples
Basic List with API Pagination
<script lang="ts">
import { InfiniteScroll } from 'sly-svelte-infinite-scroll';
interface Post {
id: number;
title: string;
body: string;
}
let posts = $state<Post[]>([]);
let page = $state(1);
async function loadMore() {
const res = await fetch(`/api/posts?page=${page}&limit=20`);
const newPosts = await res.json();
posts = [...posts, ...newPosts];
page++;
return newPosts; // Component stops when this is empty
}
</script>
<div class="posts">
{#each posts as post (post.id)}
<article>
<h2>{post.title}</h2>
<p>{post.body}</p>
</article>
{/each}
<InfiniteScroll onLoadMore={loadMore} threshold={300} />
</div>Log Viewer with Maximum Items
<script lang="ts">
import { InfiniteScroll } from 'sly-svelte-infinite-scroll';
import LogLine from './LogLine.svelte';
let logs = $state([]);
let cursor = $state('');
async function loadMore() {
// Stop after 2000 items
if (logs.length >= 2000) return [];
const res = await fetch(`/api/logs?cursor=${cursor}`);
const { items, nextCursor } = await res.json();
logs = [...logs, ...items];
cursor = nextCursor;
return items;
}
$effect(() => {
loadMore(); // Load initial data
});
</script>
<div class="log-viewer">
{#each logs as log (log.id)}
<LogLine {log} />
{/each}
<InfiniteScroll onLoadMore={loadMore} threshold={200} />
</div>Check out the full example app in the repository for a complete implementation with a device console log viewer.
