@scrollstackjs/core
v0.1.2
Published
Headless, framework-agnostic infinite-scroll engine — pagination, retry, cancellation and an intersection trigger in 1.91 KB gzipped. Zero runtime dependencies.
Maintainers
Readme
@scrollstackjs/core
The headless infinite-scroll engine — pagination, retry, cancellation, the state machine and the intersection trigger. Framework-agnostic, zero runtime dependencies, 1.91 KB gzipped.
📖 Docs · API reference · Live demo · Tutorial
npm i @scrollstackjs/coreUsing a framework? Reach for @scrollstackjs/react,
@scrollstackjs/vue or
@scrollstackjs/svelte
instead — they wrap this engine in a hook, composable or store.
Quick start
import { createInfiniteScroll } from '@scrollstackjs/core';
const scroll = createInfiniteScroll({
initialPageParam: 0,
fetchPage: async ({ pageParam, signal }) =>
(await fetch(`/api/items?cursor=${pageParam}`, { signal })).json(),
getNextPageParam: (last) => last.nextCursor, // null = no more pages
});
scroll.subscribe(() => render(scroll.getSnapshot()));
scroll.observeTarget(sentinelEl); // or call scroll.loadNextPage() yourselfThe API
Snapshot — status, fetchStatus, pages, pageParams, error,
hasNextPage, failureCount, plus the isIdle / isLoading / isSuccess /
isError / isFetching / isFetchingNextPage booleans.
Controls — subscribe, getSnapshot, observeTarget, loadNextPage,
retry, reset, destroy.
What it handles for you
- Any pagination shape. Cursor, offset and page-number are all just different
getNextPageParamimplementations — returnnull/undefinedto end the list. A0param is valid, so the engine tests with== null, never truthiness. - Two-axis state.
statusdescribes your data,fetchStatusdescribes the network. Keeping them separate is what makesisFetchingNextPagecorrect. - Load-more failures keep your data. A first-load failure is a real
error; a later-page failure leavesstatus: 'success'and setserrorso you can render a retry button without losing the list. - Stale responses stay inert. Every fetch carries a generation counter and an
AbortController, so a response landing afterreset()can't resurrect dead state. An abort counts as a cancellation, not a failure. - Retry with backoff, configurable as
boolean | number | fn. - SSR-safe. Constructs and runs with no DOM; the trigger no-ops on the server.
Learn more
| | | | ----------------------------------------------------------------------- | ------------------------------------------- | | Getting started | Install and first feed | | Core concepts | The snapshot and the two-axis state machine | | Pagination | Cursor, offset and page-number recipes | | Errors & retry | Backoff, manual retry, load-more failures | | Server rendering | What runs where | | Events & plugins | Lifecycle hooks and the plugin contract | | Architecture decisions | Why the engine is built this way |
Contributing
Issues and pull requests are welcome — see CONTRIBUTING.md.
MIT © devgauravjatt
