Pagination Component

Pagination: A navigation system that divides content into separate pages, allowing users to navigate between them while maintaining context. UIKit's pagination component is accessible, customizable, and works seamlessly across all devices.

Understanding Pagination

Pagination is essential for managing large datasets, search results, article archives, or any content that's too extensive to display on a single page.

When to Use Pagination:
  • Search results (Google-style pagination)
  • E-commerce product listings
  • Blog/article archives
  • Forum thread listings
  • Admin dashboards with data tables
  • Photo galleries or image collections
Key Benefits:
  • Improved Performance: Loads content incrementally
  • Better UX: Reduces scrolling fatigue
  • SEO Friendly: Separate URLs for each page
  • Accessibility: Keyboard navigation support
  • Mobile Responsive: Adapts to screen size
Best Practice: Consider using &qout;Load More&qout; buttons for social feeds or infinite scroll for content discovery. Use pagination when users need to bookmark specific pages or when SEO is important.

Live Examples

1. Basic Pagination

Example Preview

2. Pagination with Alignment Options

Example Preview
Left Aligned:
Center Aligned:
Right Aligned:

3. Pagination with Icons Only

Example Preview

4. Responsive Pagination

Example Preview
  • Page 2 of 20

Resize your browser to see the responsive behavior

5. Pagination with Dropdown

Example Preview
  • 1
  • 2
  • 3

JavaScript Integration

Dynamic Pagination Example:

This example shows how to integrate pagination with JavaScript for dynamic content loading.

// HTML Structure
<ul id="dynamicPagination" class="uk-pagination" uk-margin>
  <!-- Dynamic content will be inserted here -->
</ul>

<div id="contentContainer">
  <!-- Page content goes here -->
</div>

// JavaScript Implementation
class PaginationManager {
  constructor(totalPages = 20, currentPage = 1) {
    this.totalPages = totalPages;
    this.currentPage = currentPage;
    this.paginationEl = document.getElementById('dynamicPagination');
    this.contentEl = document.getElementById('contentContainer');
    
    this.init();
  }
  
  init() {
    this.renderPagination();
    this.loadPage(this.currentPage);
    this.attachEvents();
  }
  
  renderPagination() {
    let html = '';
    
    // Previous button
    if (this.currentPage > 1) {
      html += `<li><a href="#" data-page="${this.currentPage - 1}">
                <span uk-pagination-previous></span> Previous</a></li>`;
    } else {
      html += '<li class="uk-disabled"><span><span uk-pagination-previous></span> Previous</span></li>';
    }
    
    // Page numbers
    const maxVisible = 5;
    let start = Math.max(1, this.currentPage - Math.floor(maxVisible / 2));
    let end = Math.min(this.totalPages, start + maxVisible - 1);
    
    if (end - start + 1 < maxVisible) {
      start = Math.max(1, end - maxVisible + 1);
    }
    
    // First page with ellipsis
    if (start > 1) {
      html += '<li><a href="#" data-page="1">1</a></li>';
      if (start > 2) html += '<li><span>...</span></li>';
    }
    
    // Page range
    for (let i = start; i <= end; i++) {
      if (i === this.currentPage) {
        html += `<li class="uk-active"><span>${i}</span></li>`;
      } else {
        html += `<li><a href="#" data-page="${i}">${i}</a></li>`;
      }
    }
    
    // Last page with ellipsis
    if (end < this.totalPages) {
      if (end < this.totalPages - 1) html += '<li><span>...</span></li>';
      html += `<li><a href="#" data-page="${this.totalPages}">${this.totalPages}</a></li>`;
    }
    
    // Next button
    if (this.currentPage < this.totalPages) {
      html += `<li><a href="#" data-page="${this.currentPage + 1}">
                Next <span uk-pagination-next></span></a></li>`;
    } else {
      html += '<li class="uk-disabled"><span>Next <span uk-pagination-next></span></span></li>';
    }
    
    this.paginationEl.innerHTML = html;
  }
  
  loadPage(page) {
    this.currentPage = page;
    this.renderPagination();
    
    // Simulate API call
    this.contentEl.innerHTML = `<div class="uk-alert-primary" uk-alert>
      <p>Loading content for page ${page}... (Simulated API call)</p>
    </div>`;
    
    // Update URL without page reload
    window.history.pushState({page}, `Page ${page}`, `?page=${page}`);
  }
  
  attachEvents() {
    this.paginationEl.addEventListener('click', (e) => {
      e.preventDefault();
      const link = e.target.closest('a[data-page]');
      if (link) {
        const page = parseInt(link.dataset.page);
        this.loadPage(page);
      }
    });
    
    // Handle browser back/forward
    window.addEventListener('popstate', (e) => {
      if (e.state && e.state.page) {
        this.loadPage(e.state.page);
      }
    });
  }
}

// Initialize pagination
const pagination = new PaginationManager(20, 1);
Common JavaScript Methods:
// 1. Programmatically change page
function goToPage(pageNumber) {
  const pagination = new PaginationManager(20, pageNumber);
  pagination.loadPage(pageNumber);
}

// 2. Update pagination after search/filter
function updatePagination(totalItems, itemsPerPage) {
  const totalPages = Math.ceil(totalItems / itemsPerPage);
  const pagination = new PaginationManager(totalPages, 1);
}

// 3. AJAX Pagination Example
async function loadPageViaAJAX(page) {
  try {
    const response = await fetch(`/api/data?page=${page}&limit=10`);
    const data = await response.json();
    
    // Update content
    document.getElementById('content').innerHTML = data.html;
    
    // Update pagination
    const pagination = new PaginationManager(data.totalPages, page);
    
    // Update browser URL
    history.replaceState({}, '', `?page=${page}`);
  } catch (error) {
    console.error('Error loading page:', error);
    UIkit.notification('Failed to load page content', 'danger');
  }
}

// 4. Event Listeners for Custom Controls
document.addEventListener('DOMContentLoaded', function() {
  // Custom "Go to page" input
  const goToPageInput = document.getElementById('goToPage');
  const goToPageButton = document.getElementById('goToPageBtn');
  
  goToPageButton.addEventListener('click', function() {
    const page = parseInt(goToPageInput.value);
    if (page && page > 0) {
      goToPagePage(page);
    }
  });
  
  // Keyboard shortcuts
  document.addEventListener('keydown', function(e) {
    if (e.key === 'ArrowLeft') {
      // Previous page
      pagination.loadPage(Math.max(1, pagination.currentPage - 1));
    } else if (e.key === 'ArrowRight') {
      // Next page
      pagination.loadPage(Math.min(pagination.totalPages, 
        pagination.currentPage + 1));
    }
  });
});

Complete Production Example

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>UIKit Pagination - Complete Example</title>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/uikit@3.19.2/dist/css/uikit.min.css" />
    <style>
        :root {
            --pagination-active-bg: #1e87f0;
            --pagination-active-color: #fff;
            --pagination-hover-bg: #f8f8f8;
        }
        
        .custom-pagination .uk-active > span {
            background-color: var(--pagination-active-bg);
            color: var(--pagination-active-color);
            border-radius: 3px;
        }
        
        .custom-pagination a:hover {
            background-color: var(--pagination-hover-bg);
            border-radius: 3px;
        }
        
        .results-info {
            font-size: 0.9rem;
            color: #666;
        }
        
        @media (max-width: 640px) {
            .pagination-info {
                flex-direction: column;
                align-items: flex-start !important;
            }
        }
    </style>
</head>
<body>
    <div class="uk-container uk-container-expand uk-margin-top">
        <h1>Product Catalog</h1>
        
        <!-- Results information -->
        <div class="uk-flex uk-flex-between uk-flex-middle pagination-info uk-margin-bottom">
            <div class="results-info">
                Showing 1-10 of 200 products
            </div>
            <div class="uk-form-controls">
                <label for="itemsPerPage" class="uk-form-label">Items per page:</label>
                <select id="itemsPerPage" class="uk-select uk-form-width-small">
                    <option value="10">10</option>
                    <option value="25">25</option>
                    <option value="50">50</option>
                    <option value="100">100</option>
                </select>
            </div>
        </div>
        
        <!-- Main pagination -->
        <ul class="uk-pagination uk-flex-center custom-pagination" uk-margin>
            <li><a href="#"><span uk-pagination-previous></span></a></li>
            <li><a href="#">1</a></li>
            <li class="uk-active"><span>2</span></li>
            <li><a href="#">3</a></li>
            <li><a href="#">4</a></li>
            <li><a href="#">5</a></li>
            <li><span>...</span></li>
            <li><a href="#">20</a></li>
            <li><a href="#"><span uk-pagination-next></span></a></li>
        </ul>
        
        <!-- Content area -->
        <div class="uk-grid uk-grid-small uk-child-width-1-2@s uk-child-width-1-3@m uk-child-width-1-4@l" uk-grid>
            <!-- Product cards would go here -->
        </div>
        
        <!-- Bottom pagination -->
        <div class="uk-margin-large-top">
            <ul class="uk-pagination uk-flex-center" uk-margin>
                <li><a href="#"><span uk-pagination-previous></span> Previous</a></li>
                <li><a href="#">1</a></li>
                <li class="uk-active"><span>2</span></li>
                <li><a href="#">3</a></li>
                <li><a href="#">4</a></li>
                <li><a href="#">5</a></li>
                <li><span>...</span></li>
                <li><a href="#">20</a></li>
                <li><a href="#">Next <span uk-pagination-next></span></a></li>
            </ul>
        </div>
        
        <!-- Jump to page -->
        <div class="uk-flex uk-flex-center uk-margin-top">
            <div class="uk-inline">
                <form class="uk-form">
                    <div class="uk-flex">
                        <input class="uk-input uk-form-width-small" 
                               type="number" 
                               min="1" 
                               max="20" 
                               placeholder="Page" 
                               id="jumpToPage">
                        <button class="uk-button uk-button-default" 
                                type="button" 
                                id="jumpBtn">
                            Go
                        </button>
                    </div>
                </form>
            </div>
        </div>
    </div>

    <!-- UIKit JS -->
    <script src="https://cdn.jsdelivr.net/npm/uikit@3.19.2/dist/js/uikit.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/uikit@3.19.2/dist/js/uikit-icons.min.js"></script>
    
    <script>
        // Enhanced Pagination with all features
        document.addEventListener('DOMContentLoaded', function() {
            const pagination = {
                currentPage: 2,
                totalPages: 20,
                itemsPerPage: 10,
                
                init() {
                    this.setupEventListeners();
                    this.updateResultsInfo();
                },
                
                setupEventListeners() {
                    // Page click handlers
                    document.querySelectorAll('.uk-pagination a').forEach(link => {
                        link.addEventListener('click', (e) => {
                            e.preventDefault();
                            this.handlePageClick(e.target);
                        });
                    });
                    
                    // Items per page change
                    document.getElementById('itemsPerPage').addEventListener('change', (e) => {
                        this.itemsPerPage = parseInt(e.target.value);
                        this.recalculatePages();
                        this.updateResultsInfo();
                    });
                    
                    // Jump to page
                    document.getElementById('jumpBtn').addEventListener('click', () => {
                        this.jumpToPage();
                    });
                    
                    // Enter key in jump input
                    document.getElementById('jumpToPage').addEventListener('keypress', (e) => {
                        if (e.key === 'Enter') {
                            e.preventDefault();
                            this.jumpToPage();
                        }
                    });
                },
                
                handlePageClick(element) {
                    const link = element.closest('a');
                    if (!link) return;
                    
                    const text = link.textContent.trim();
                    
                    if (text.includes('Previous') || link.querySelector('[uk-pagination-previous]')) {
                        this.goToPage(Math.max(1, this.currentPage - 1));
                    } else if (text.includes('Next') || link.querySelector('[uk-pagination-next]')) {
                        this.goToPage(Math.min(this.totalPages, this.currentPage + 1));
                    } else if (!isNaN(parseInt(text))) {
                        this.goToPage(parseInt(text));
                    }
                },
                
                goToPage(page) {
                    if (page === this.currentPage) return;
                    
                    // Update active state
                    document.querySelectorAll('.uk-pagination .uk-active').forEach(el => {
                        el.classList.remove('uk-active');
                    });
                    
                    // Find and activate the clicked page
                    document.querySelectorAll('.uk-pagination a').forEach(link => {
                        if (parseInt(link.textContent) === page) {
                            link.parentNode.classList.add('uk-active');
                            link.outerHTML = `<span>${page}</span>`;
                        }
                    });
                    
                    this.currentPage = page;
                    this.updateResultsInfo();
                    this.loadPageContent(page);
                    
                    // Scroll to top smoothly
                    window.scrollTo({ top: 0, behavior: 'smooth' });
                    
                    // Show notification
                    UIkit.notification({
                        message: `Loaded page ${page}`,
                        status: 'success',
                        pos: 'top-center',
                        timeout: 1000
                    });
                },
                
                jumpToPage() {
                    const input = document.getElementById('jumpToPage');
                    const page = parseInt(input.value);
                    
                    if (page && page >= 1 && page <= this.totalPages) {
                        this.goToPage(page);
                        input.value = '';
                    } else {
                        UIkit.notification({
                            message: `Please enter a page between 1 and ${this.totalPages}`,
                            status: 'warning',
                            pos: 'top-center'
                        });
                    }
                },
                
                recalculatePages() {
                    // In a real app, you would recalculate total pages based on items
                    // For this example, we'll simulate it
                    this.totalPages = Math.ceil(200 / this.itemsPerPage);
                    this.updatePaginationUI();
                },
                
                updatePaginationUI() {
                    // Update pagination controls based on new total pages
                    // This is simplified - in reality you'd regenerate the pagination
                    console.log(`Updated to ${this.totalPages} total pages`);
                },
                
                updateResultsInfo() {
                    const start = (this.currentPage - 1) * this.itemsPerPage + 1;
                    const end = Math.min(this.currentPage * this.itemsPerPage, 200);
                    
                    document.querySelector('.results-info').textContent = 
                        `Showing ${start}-${end} of 200 products`;
                },
                
                loadPageContent(page) {
                    // Simulate loading content
                    console.log(`Loading content for page ${page}...`);
                    
                    // In a real application, you would:
                    // 1. Show loading spinner
                    // 2. Make AJAX request to fetch page data
                    // 3. Update the content area
                    // 4. Hide loading spinner
                }
            };
            
            pagination.init();
            
            // Keyboard navigation
            document.addEventListener('keydown', (e) => {
                if (e.key === 'ArrowLeft' && !e.target.matches('input, textarea')) {
                    pagination.goToPage(Math.max(1, pagination.currentPage - 1));
                } else if (e.key === 'ArrowRight' && !e.target.matches('input, textarea')) {
                    pagination.goToPage(Math.min(pagination.totalPages, pagination.currentPage + 1));
                }
            });
        });
    </script>
</body>
</html>

Pagination Best Practices

Accessibility
  • Use semantic HTML (<nav> element)
  • Provide ARIA labels for screen readers
  • Ensure keyboard navigation works
  • Add proper focus states
  • Use descriptive link text
UX Considerations
  • Show current page clearly
  • Include Previous/Next buttons
  • Add &qout;First&qout; and &qout;Last&qout; for many pages
  • Consider mobile touch targets
  • Provide page number input for large datasets
Performance
  • Implement AJAX pagination for SPAs
  • Use URL parameters for bookmarking
  • Cache frequently accessed pages
  • Lazy load page content
  • Consider infinite scroll for certain use cases
When to Use Different Pagination Patterns:
  • Numbered Pagination: Search results, e-commerce, blogs
  • &qout;Load More&qout; Button: Social feeds, news sites
  • Infinite Scroll: Content discovery, image galleries
  • Table Pagination: Admin dashboards, data tables

Related UIKit Components

Tab

For content within the same page context

Accordion

For vertically collapsing content sections

Slider

For horizontal content navigation

Breadcrumb

For hierarchical navigation

Summary

UIKit's Pagination component provides a robust, accessible foundation for page navigation. When implementing pagination:

  1. Choose the right pattern for your content type
  2. Ensure accessibility for all users
  3. Optimize for both desktop and mobile
  4. Consider implementing AJAX for smoother UX
  5. Test with real users to validate your implementation

For complex implementations, consider combining pagination with UIKit's Filter and Sort components for complete data navigation solutions.