Pagination Controls
Pagination helps users navigate through large datasets by breaking content into manageable pages. Our pagination component offers flexible display options from simple prev/next buttons to full numbered navigation.
Interactive Demo
Simple Navigation
Previous/next buttons without page numbers
Usage
<script>
import PaginationControls from '$lib/shared/components/navigation/PaginationControls.svelte';
let currentPage = $state(1);
const totalPages = 10;
function handlePageChange(page) {
currentPage = page;
// Load data for the new page
}
</script>
<PaginationControls
{currentPage}
{totalPages}
onPageChange={handlePageChange}
showPageNumbers={true}
/> API Reference
Props
| Prop | Type | Default | Description |
|---|---|---|---|
currentPage | number | required | Current active page number |
totalPages | number | required | Total number of pages |
onPageChange | (page: number) => void | required | Callback when page changes |
showPageNumbers | boolean | false | Show clickable page numbers |
maxVisiblePages | number | 5 | Max page numbers to display |
class | string | '' | Additional CSS classes |
Features
Simple Navigation
Basic previous/next buttons without page numbers:
<PaginationControls
currentPage={page}
totalPages={10}
onPageChange={handlePageChange}
/> Numbered Pages
Direct navigation to specific pages:
<PaginationControls
currentPage={page}
totalPages={20}
onPageChange={handlePageChange}
showPageNumbers={true}
maxVisiblePages={7}
/> Compact Mode
Fewer visible pages for constrained spaces:
<PaginationControls
currentPage={page}
totalPages={100}
onPageChange={handlePageChange}
showPageNumbers={true}
maxVisiblePages={3}
class="pagination-compact"
/> State Management
Edge Cases
The component automatically handles edge cases:
- First page: Previous button disabled
- Last page: Next button disabled
- Single page: Consider hiding pagination entirely
- Invalid page: Clamps to valid range
Loading States
Show loading feedback during page transitions:
{#if isLoading}
<div class="loading-overlay">
<Spinner />
</div>
{/if}
<PaginationControls {...props} /> Styling
CSS Variables
Customize appearance with CSS variables:
--typography-caption-size /* Page number size */
--typography-caption-color /* Inactive page color */
--typography-body-color /* Active page color */
--primary /* Active page accent */
--neutral-200 /* Disabled state */ Custom Classes
Apply custom styles via the class prop:
:global(.pagination-compact) {
padding: var(--space-2);
}
:global(.pagination-compact button) {
padding: var(--space-1) var(--space-2);
font-size: var(--typography-caption-size);
} Accessibility
Keyboard Navigation
- Tab/Shift+Tab: Navigate between controls
- Enter/Space: Activate focused button
- Arrow keys: Optional navigation between pages
ARIA Labels
The component includes proper ARIA attributes:
aria-labelfor previous/next buttonsaria-current="page"for active pagearia-disabledfor disabled states
Screen Reader Support
- Announces current page and total pages
- Provides context for navigation actions
- Clear button labels for all controls
Design Patterns
With Item Count
Show total items and current range:
<div class="pagination-wrapper">
<span class="item-count">
Showing {startItem}-{endItem} of {totalItems} items
</span>
<PaginationControls {...props} />
</div> With Page Size Selector
Allow users to control items per page:
<div class="pagination-controls">
<select bind:value={pageSize}>
<option value={10}>10 per page</option>
<option value={25}>25 per page</option>
<option value={50}>50 per page</option>
</select>
<PaginationControls {...props} />
</div> URL Synchronization
Keep pagination state in URL:
import { page } from '$app/stores';
import { goto } from '$app/navigation';
function handlePageChange(newPage) {
const url = new URL($page.url);
url.searchParams.set('page', newPage);
goto(url.toString());
} Performance
Data Loading
Optimize data fetching strategies:
- Prefetch adjacent pages for instant navigation
- Cache visited pages to avoid re-fetching
- Show skeleton UI during loading
- Implement virtual scrolling for very large datasets
Rendering Optimization
- Use
{#key}blocks for smooth transitions - Debounce rapid page changes
- Lazy load page content
- Consider infinite scroll for mobile
Common Patterns
Table Pagination
<div class="table-container">
<table>
<!-- Table content -->
</table>
<div class="table-footer">
<PaginationControls
{currentPage}
{totalPages}
onPageChange={loadTablePage}
showPageNumbers={true}
/>
</div>
</div> Search Results
<div class="search-results">
<div class="results-header">
<h2>{totalResults} results found</h2>
<span>Page {currentPage} of {totalPages}</span>
</div>
<div class="results-list">
{#each results as result}
<SearchResult {result} />
{/each}
</div>
<PaginationControls {...props} />
</div> Gallery Grid
<div class="gallery">
<div class="gallery-grid">
{#each items as item}
<GalleryItem {item} />
{/each}
</div>
<PaginationControls
{currentPage}
{totalPages}
onPageChange={loadGalleryPage}
class="gallery-pagination"
/>
</div> Best Practices
- Show context: Always indicate current position (e.g., “Page 3 of 10”)
- Predictable behavior: Keep consistent pagination across your app
- Smart defaults: Choose appropriate page size for content type
- Mobile consideration: Use simple prev/next on small screens
- Performance: Implement proper caching and prefetching
- Accessibility: Test with keyboard and screen readers
Related Components
- Tab Navigation: For switching between views
- Table of Contents: For document navigation
- Infinite Scroll: Alternative for continuous content