Infinite scroll for Svelte 5 with Runes
npm install svelte-infinite






β¨ Flexible
β° Infinite Loop Detection
π£ Control Loader State
π IntersectionObserver based
π₯ Using Runes and Snippets
π§βπ§ Demo: svelte-5-infinite.vercel.app
> [!WARNING]
> v0.5.0 contains a breaking change. See this PR for more details including migration steps.
1. Install svelte-infinite
``bash`
npm install svelte-infinite
pnpm install svelte-infinite
yarn add svelte-infinite
2. Import both InfiniteLoader and LoaderState from svelte-infinite
`svelte
{#each allItems as user (user.id)}
{user.name}
{/each}
`
This is a more realistic example use-case which includes a paginated data endpoint that your triggerLoad function should hit every time it's called to load more data. It also includes the use of some of the optional snippets to render custom markup inside the loader component.
`svelte
{#each allItems as user (user.id)}
{/each}
{#snippet loading()}
Loading...
{/snippet}
{#snippet error(load)}
βΎοΈ Usage
This package consists of two parts, first the
InfiniteLoader component which is a wrapper around your items. It will trigger whichever async function you've passed to the triggerLoad prop when the user scrolls to the bottom of the list.Second, there is also a
LoaderState class which you should use to interact with the internal state of the loader. For example, if your fetch call errored, or you've reached the maximum number of items, etc. you can communicate that to the loader. The most basic usage example can be seen in the 'Getting Started' section above. A more complex example can be seen in the 'Example' section, and of course the application in /src/routes/+page.svelte in this repository also has a "real world" usage example.> [!WARNING]
> As of
0.5.0 the LoaderState import is not an instance of the class, but the class itself. Meaning you'll need to instantiate it yourself with new LoaderState() per component instance. This gives the user more flexibility when trying to use multiple svelte-infinite instances per page, as well as resetting the state.$3
The
loaderState controller has 4 methods on it. You should call these at the appropriate times to control the internal state of the InfiniteLoader.-
loaderState.loaded()
- Designed to be called after a successful fetch. Will set the internal state back to READY so another fetch can be attempted.
- loaderState.error()
- Designed to be called after a failed fetch or any other error. This will cause the InfiniteLoader to render a "Retry" button by default, or the error snippet.
- loaderState.complete()
- Designed to be called when you've reached the end of your list and there are no more items to fetch. This will render a "No more data" string, or the noData snippet.
- loaderState.reset()
- Designed to be called when you want to reset the state of the InfiniteLoader to its initial state, for example if there is a search input tied to your data and the user enters a new query.$3
-
loaderState: LoaderState
- An instance of the LoaderState class.
- triggerLoad: () => Promise - required
- The async function to call when we should attempt to load more data to show.
- intersectionOptions: IntersectionObserverInit = { rootMargin: "0px 0px 200px 0px" } - optional
- The options to pass to the IntersectionObserver instance. See MDN for more details. The default rootMargin value will cause the target to intersect 200px earlier and trigger the loadMore function before it actually intersects with the root element (window by default). This has the effect of beginning to load the next page of data before the user has actually reached the current bottom of the list, making the experience feel more smooth.
- If you are using a separate scroll container (element with overflow-y: scroll) other than the window / viewport, then it might be necessary for you to also pass a custom root element here.
- loopTimeout: number = 3000 - optional
- Length of the cool down period (in milliseconds).
- loopDetectionTimeout: number = 2000 - optional
- The time in milliseconds in which the loopMaxCalls count must be hit in order to trigger a cool down period.
- loopMaxCalls: number = 5 - optional
- The limit of triggerLoad executions which will trigger a cool down period, if reached within the loopDetectionTimeout.$3
Snippets replace slots in Svelte 5, and as such are used here to customize the content shown at the bottom of the scroller in various states. The
InfiniteLoader component has 5 snippet "slots" available.-
loading
- Shown while calling triggerLoad and waiting on a response.
- noResults
- Shown when there are no more results to display and we haven't fetched any data yet (i.e. data is less than count of items to be shown on first "page").
- noData
- Shown when loaderState.complete() is called, indicating we've fetched and displayed all available data.
- coolingOff
- Shown when loaderState !== "COMPLETE" and a loop has been detected. Will disappear and loopTimeout when the cooling off period expires.
- error
- Shown when there is an error or loaderState.error() has been called. The snippet has an attemptLoad parameter passed to it which is just the internal triggerLoad` function, designed for a "Retry" button or similar.- Initially inspired by jonasgeiler/svelte-infinite-loading
- Open to contributions, issues, and feedback π
MIT