Skip to main content

Pagination Controls

Navigate through paginated content with flexible display options

Tags:
navigationpaginationuicomponentsaccessibility
Last updated: 2025-09-12T00:00:00.000Z

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

3 / 10
Page 3 of 10

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

PropTypeDefaultDescription
currentPagenumberrequiredCurrent active page number
totalPagesnumberrequiredTotal number of pages
onPageChange(page: number) => voidrequiredCallback when page changes
showPageNumbersbooleanfalseShow clickable page numbers
maxVisiblePagesnumber5Max page numbers to display
classstring''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-label for previous/next buttons
  • aria-current="page" for active page
  • aria-disabled for 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:

  1. Prefetch adjacent pages for instant navigation
  2. Cache visited pages to avoid re-fetching
  3. Show skeleton UI during loading
  4. 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>
<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

  1. Show context: Always indicate current position (e.g., “Page 3 of 10”)
  2. Predictable behavior: Keep consistent pagination across your app
  3. Smart defaults: Choose appropriate page size for content type
  4. Mobile consideration: Use simple prev/next on small screens
  5. Performance: Implement proper caching and prefetching
  6. Accessibility: Test with keyboard and screen readers
  • Tab Navigation: For switching between views
  • Table of Contents: For document navigation
  • Infinite Scroll: Alternative for continuous content