JAVASCRIPT

Implement Infinite Scroll Pagination for API Data

Create a seamless user experience by implementing infinite scroll pagination using JavaScript's Fetch API and Intersection Observer to load more data as users scroll.

// index.html
/*
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Infinite Scroll API Pagination</title>
    <style>
        body { font-family: sans-serif; margin: 20px; }
        .item { border: 1px solid #eee; padding: 10px; margin-bottom: 10px; }
        .loading { text-align: center; padding: 20px; font-style: italic; color: #888; }
    </style>
</head>
<body>
    <h1>Posts</h1>
    <div id="posts-container"></div>
    <div id="loading" class="loading">Loading more posts...</div>
    <script src="app.js"></script>
</body>
</html>
*/

// app.js
let currentPage = 1;
const postsPerPage = 10;
const postsContainer = document.getElementById('posts-container');
const loadingIndicator = document.getElementById('loading');
let isLoading = false;
let hasMore = true; // Assume there's more data initially

// Function to fetch posts from a dummy API
async function fetchPosts(page) {
    isLoading = true;
    loadingIndicator.style.display = 'block';

    try {
        // Using JSONPlaceholder for dummy data
        const response = await fetch(`https://jsonplaceholder.typicode.com/posts?_page=${page}&_limit=${postsPerPage}`);
        if (!response.ok) {
            throw new Error(`HTTP error! status: ${response.status}`);
        }
        const posts = await response.json();
        
        if (posts.length === 0 || posts.length < postsPerPage) {
            hasMore = false; // No more data to load
        }
        
        posts.forEach(post => {
            const postElement = document.createElement('div');
            postElement.classList.add('item');
            postElement.innerHTML = `
                <h3>${post.title}</h3>
                <p>${post.body}</p>
                <small>Post ID: ${post.id}</small>
            `;
            postsContainer.appendChild(postElement);
        });
        currentPage++;

    } catch (error) {
        console.error('Error fetching posts:', error);
        loadingIndicator.textContent = 'Failed to load posts.';
    } finally {
        isLoading = false;
        if (!hasMore) {
            loadingIndicator.textContent = 'No more posts to load.';
        } else {
            loadingIndicator.style.display = 'none';
        }
    }
}

// Set up Intersection Observer
const observer = new IntersectionObserver((entries) => {
    entries.forEach(entry => {
        // If the loading indicator is visible and we're not already loading and there's more data
        if (entry.isIntersecting && !isLoading && hasMore) {
            fetchPosts(currentPage);
        }
    });
}, {
    root: null, // observe against the viewport
    rootMargin: '0px', // no margin
    threshold: 1.0 // trigger when 100% of the target is visible
});

// Start observing the loading indicator element
observer.observe(loadingIndicator);

// Initial load (optional, or let observer handle it on first scroll)
// fetchPosts(currentPage);
How it works: This JavaScript snippet implements an infinite scroll pagination pattern. It uses the Fetch API to retrieve data from a paginated API and the `IntersectionObserver` API to detect when the user scrolls near the bottom of the page. When the `loadingIndicator` element comes into view, the `fetchPosts` function is triggered to load the next set of data. This provides a smooth, continuous loading experience without requiring users to click "next page" buttons. `isLoading` and `hasMore` flags prevent redundant fetches and indicate when all data has been loaded.

Need help integrating this into your project?

Our team of expert developers can help you build your custom application from scratch.

Hire DigitalCodeLabs