Infinite Scroll Plus - Flutter Package with local search and sort option
Pagination is one of those problems every Flutter developer faces repeatedly. I found myself wiring ScrollControllers, tracking offsets, debouncing API calls, handling loading states and errors… and suddenly a simple list turns into a mini framework. After doing this across multiple projects, I decided to design a clean, reusable, and scalable solution — and thus Infinite Scroll Plus was born.
This article explains why it exists, what problems it solves, and how to use it effectively — with minimal cognitive load.
Most infinite scroll implementations fall into one of these traps:
Too much boilerplate for a common use case
UI tightly coupled with API logic
Hard to customize loading / error / empty states
No real support for backend pagination (page / cursor)
Infinite Scroll Plus focuses on:
✅ Clear mental model
✅ Explicit backend control
✅ Customizable UI without complexity
✅ Production-ready defaults
📜 InfiniteScrollList (ListView)
🟦 InfiniteScrollGrid (GridView)
🦴 Skeleton loader for initial loading
🔁 Pagination via LoadMoreRequest
🔍 Search & sort support
⚠️ Error handling with retry
🎨 Fully customizable loading, empty & error states
No magic. No hidden state.

infinite_scroll_plus demo
dependencies:
infinite_scroll_plus: <l>LoadMoreRequestInstead of guessing offsets or managing scroll math, Infinite Scroll Plus gives you a clean request object:
class LoadMoreRequest {
final int currentItemCount;
final int page;
final Object? cursor;
}This means:
Page-based APIs? ✅
Offset-based APIs? ✅
Cursor-based APIs? ✅
The widget suggests, you decide.
InfiniteScrollList<String>(
items: items,
hasMore: hasMore,
onLoadMore: (request) async {
final newItems = await fetchItems(page: request.page);
items.addAll(newItems);
},
itemBuilder: (context, item, index) => ListTile(
title: Text(item),
),
);That’s it. No controller. No listeners. No lifecycle traps.
For initial loading states, skeletons feel faster and smoother than spinners.
InfiniteScrollList<String>(
items: items,
onLoadMore: _loadMore,
enableSkeletonLoader: true,
skeletonWidget: MyCustomSkeleton(),
);Skeletons appear only when the list is empty — exactly when users expect them.
Network failures are normal. Ignoring them isn’t.
InfiniteScrollList<String>(
items: items,
hasMore: hasMore,
onLoadMore: _loadMore,
errorBuilder: (context, error, retry) {
return Column(
children: [
Text('Failed to load items'),
ElevatedButton(
onPressed: retry,
child: const Text('Retry'),
),
],
);
},
);Error UI is optional
Retry logic is handled for you
No duplicated state management
Sometimes you just want local filtering — not another API call.
InfiniteScrollList<String>(
items: items,
searchQuery: searchQuery,
onSearch: (items, query) => items
.where((e) => e.toLowerCase().contains(query.toLowerCase()))
.toList(),
applySort: true,
onSort: (items) {
items.sort();
return items;
},
);The widget stays declarative. Your logic stays readable.
Switching to a grid doesn’t change anything:
InfiniteScrollGrid<String>(
items: items,
onLoadMore: _loadMore,
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 12,
mainAxisSpacing: 12,
),
itemBuilder: (context, item, index) => Card(
child: Center(child: Text(item)),
),
);Same API. Same behavior. Zero relearning.
Yes, v2.0 introduces breaking changes — intentionally.
onLoadMore now receives LoadMoreRequest
Error handling is explicit
Skeleton loader is opt-in
Because clarity beats convenience in production code.
You now control:
Pagination strategy
Error behavior
Loading experience
Infinite Scroll Plus follows three principles:
UI should not own business logic
Explicit APIs reduce bugs
Common things should be simple
It doesn’t try to be a state management solution. It doesn’t force an architecture. It just solves infinite scrolling — properly.
Perfect for:
REST / GraphQL pagination
Admin panels
Feeds & dashboards
Search results
Catalogs & listings
If you’ve ever rewritten pagination logic twice — this is for you.
This package represents my approach to infinite scroll in Flutter — clean, scalable, and production-ready. With Infinite Scroll Plus, you get:
Less boilerplate
Clear contracts
Better UX
Cleaner code
I hope it saves you the time and complexity it once cost me.
Happy building 💙
0
3
0