How to implement pagination with SwiftUI's List view
Learn how to implement infinite scrolling with SwiftUI.
27 Apr 2026 · 5 min read
When working with larger datasets, loading everything at once is often unnecessary. In many cases, we want to fetch an initial page of results and then load more content as the user scrolls.
SwiftUI's List works well for this pattern. By combining it with asynchronous loading and a small amount of pagination state, we can build a predictable infinite scrolling experience without much code.
In this article, we’ll look at how to implement pagination with List by loading the next page once the user reaches the end of the list.
Let's dive in.

Approach overview
Pagination can be implemented in different ways. In this article, we focus on infinite scrolling, where new content is loaded automatically as the user reaches the end of the list.
A simple and effective way to achieve this is to add a dedicated "loading row" at the bottom of the list.
When this row becomes visible, we trigger the next page request.
Implementing the list
We start by rendering the current items and conditionally adding the loading row:
List {ForEach(viewModel.items, id: \.id) { item inListItemView(item: item)}if viewModel.isMoreDataAvailable {lastRowView}}
The key idea here is that the loading row is only shown when more data can be loaded.
Triggering pagination
The loading row is responsible for triggering the next page request when it appears on screen:
var lastRowView: some View {ZStack {switch viewModel.paginationState {case .isLoading:ProgressView()case .error(let error):ErrorView(error)}}.frame(height: 50).onAppear {viewModel.loadMoreItems()}}
When the user scrolls to the end of the list, this row becomes visible and its onAppear modifier is triggered.
This is the moment where we load the next page.
Managing pagination state
The loading row also gives us a clear place to represent the current pagination state. For example, we can show a progress indicator while loading or display an error view with a retry option when the request fails.
This makes the behavior predictable and easy to extend.
The implementation of loadMoreItems() should ensure that repeated onAppear calls do not start multiple pagination requests before the previous one has finished.
Conclusion
Using a dedicated loading row is a simple and predictable way to implement pagination with SwiftUI's List.
By triggering the next page when this row becomes visible, we can build an infinite scrolling experience that is easy to understand and extend.



Newsletter
Like to support my work?
Say hi
Related tags
Articles with related topics
Latest articles and tips



