Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Generates pagination infrastructure with offset or cursor-based patterns, infinite scroll, and search support. Use when user wants to add paginated lists, infinite scrolling, or load-more functionality.
.claude/skills/rshankras-pagination/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-07 | ✗→✓ | ▲ Improved | 30% | 0% |
| case-14 | ✗→✓ | ▲ Improved | 35% | 0% |
| case-15 | ✗→✓ | ▲ Improved | 21% | 0% |
| case-17 | ✗→✓ | ▲ Improved | 28% | 0% |
| case-11 | ✓→✗ | ▼ Worse | 30% | 0% |
Generate production pagination infrastructure supporting offset-based and cursor-based APIs, with infinite scroll SwiftUI views, state machine management, and optional search integration.
Use this skill when the user:
Search for existing networking code:
Glob: **/*API*.swift, **/*Client*.swift, **/*Endpoint*.swift
Grep: "APIClient" or "APIEndpoint"If networking-layer generator was used, detect the APIEndpoint protocol and generate data sources that conform to it.
Search for existing pagination:
Glob: **/*Pagina*.swift, **/*LoadMore*.swift
Grep: "PaginationState" or "loadNextPage" or "hasMorePages"If found, ask user whether to replace or extend.
Ask user via AskUserQuestion:
Read pagination-patterns.md for architecture guidance. Read templates.md for production Swift code.
Generate these files:
PaginatedResponse.swift — Generic response models for offset and cursorPaginationState.swift — State machine (idle, loading, loaded, error, exhausted)PaginatedDataSource.swift — Protocol endpoints conform toPaginationManager.swift — @Observable manager with state transitionsBased on configuration:
SearchablePaginationManager.swift — If search selectedViews/PaginatedList.swift — Infinite scroll SwiftUI wrapperViews/LoadMoreButton.swift — Manual load-more buttonViews/PaginationStateView.swift — Empty/loading/error state viewsCheck project structure:
Sources/ exists → Sources/Pagination/App/ exists → App/Pagination/Pagination/After generation, provide:
Pagination/
├── PaginatedResponse.swift # Generic response models
├── PaginationState.swift # State machine enum
├── PaginatedDataSource.swift # Data source protocol
├── PaginationManager.swift # @Observable manager
├── SearchablePaginationManager.swift # Optional: search + pagination
└── Views/
├── PaginatedList.swift # Infinite scroll wrapper
├── LoadMoreButton.swift # Manual load-more
└── PaginationStateView.swift # Empty/loading/error statesDefine a data source:
swiftstruct UsersDataSource: PaginatedDataSource { typealias Item = User let apiClient: APIClient func fetch(page: PageRequest) async throws -> PaginatedResponse<User> { try await apiClient.request(UsersEndpoint(page: page.page, size: page.size)) } }
Use PaginationManager in a view model:
swift@Observable final class UsersViewModel { let pagination: PaginationManager<UsersDataSource> init(apiClient: APIClient) { pagination = PaginationManager( dataSource: UsersDataSource(apiClient: apiClient) ) } }
With SwiftUI (infinite scroll):
swiftstruct UsersListView: View { @State private var viewModel = UsersViewModel() var body: some View { PaginatedList(manager: viewModel.pagination) { user in UserRow(user: user) } .task { await viewModel.pagination.loadFirstPage() } } }
With search:
swiftstruct SearchableUsersView: View { @State private var searchManager = SearchablePaginationManager( dataSource: UsersDataSource() ) var body: some View { PaginatedList(manager: searchManager.pagination) { user in UserRow(user: user) } .searchable(text: $searchManager.query) } }
swift@Test func loadFirstPagePopulatesItems() async throws { let mockSource = MockDataSource(items: User.mockList(count: 20)) let manager = PaginationManager(dataSource: mockSource, pageSize: 10) await manager.loadFirstPage() #expect(manager.items.count == 10) #expect(manager.state == .loaded) #expect(manager.hasMore == true) } @Test func loadAllPagesReachesExhausted() async throws { let mockSource = MockDataSource(items: User.mockList(count: 15)) let manager = PaginationManager(dataSource: mockSource, pageSize: 10) await manager.loadFirstPage() await manager.loadNextPage() #expect(manager.items.count == 15) #expect(manager.state == .exhausted) }
generators/networking-layer — Base networking layer for data sourcesgenerators/http-cache — Cache paginated responsesOther measured skills in the registry, with their headline benchmark lift.