How to Add Pagination to a Static HTML Blog Using JSON, CSS, and JavaScript

Adding pagination to a static HTML blog helps visitors browse content more easily when the number of posts grows. In the example above, the blog displays five posts per page and automatically generates navigation buttons so readers can move between pages without loading an excessively long list of articles.

How to Add Pagination to a Static HTML Blog Using JSON, CSS, and JavaScript


The pagination system works by loading data from a JSON file, calculating the total number of pages, displaying only the posts that belong to the current page, and generating navigation controls dynamically with JavaScript. This approach is lightweight and suitable for static websites hosted on platforms such as GitHub Pages.

Here is full code in HTML

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>085773009666 Bandarnya Laundry Kiloan Dan Satuan Di Jakarta Dan Purwokerto</title>
  <link rel="stylesheet" href="/blog/styles.css">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css">
</head>
<body>
  <div id="header"></div>
  
  <div class="content">
    <h2>Postingan Terbaru</h2>
    <div id="post-list" class="post-list"></div>
    <div id="pagination" class="pagination"></div>
  </div>

  <div id="footer"></div>

  <script>
    const POSTS_PER_PAGE = 5;

    function loadElement(url, elementId) {
      return fetch(url)
        .then(response => {
          if (!response.ok) throw new Error(`Error loading ${url}`);
          return response.text();
        })
        .then(html => {
          document.getElementById(elementId).innerHTML = html;
        })
        .catch(error => {
          console.error(error);
          document.getElementById(elementId).innerHTML = 
            `<div class="error">Error loading ${elementId}</div>`;
        });
    }

    Promise.all([
      loadElement('/blog/header.html', 'header'),
      loadElement('/blog/footer.html', 'footer'),
      fetch('/blog/posts.json').then(response => response.json())
    ]).then(([_, __, posts]) => {
      document.getElementById('year').textContent = new Date().getFullYear();

      const currentPage = parseInt(new URLSearchParams(window.location.search).get('page')) || 1;
      const totalPages = Math.ceil(posts.length / POSTS_PER_PAGE);
      const startIndex = (currentPage - 1) * POSTS_PER_PAGE;
      const paginatedPosts = posts.slice(startIndex, startIndex + POSTS_PER_PAGE);

      const postList = document.getElementById('post-list');
      postList.innerHTML = paginatedPosts.map(post => `
        <div class="post-item">
          <h3><a href="${post.url}">${post.title}</a></h3>
          <p>${post.date}</p>
          <p>${post.excerpt}</p>
        </div>
      `).join('');

      const pagination = document.getElementById('pagination');
      pagination.innerHTML = `
        <button onclick="changePage(${currentPage - 1})" ${currentPage === 1 ? 'disabled' : ''}>Newer</button>
        ${Array.from({length: totalPages}, (_, i) => i + 1).map(page => `
          <button onclick="changePage(${page})" ${currentPage === page ? 'class="active"' : ''}>${page}</button>
        `).join('')}
        <button onclick="changePage(${currentPage + 1})" ${currentPage === totalPages ? 'disabled' : ''}>Older</button>
      `;
    }).catch(error => console.error(error));

    window.changePage = (page) => {
      const url = new URL(window.location);
      url.searchParams.set('page', page);
      window.history.pushState({}, '', url);
      location.reload();
    };
  </script>
</body>
</html>

JSON

<!-- posts.json -->
[
  {
    "title": "My First Blog Post",
    "date": "January 1, 2023",
    "excerpt": "This is a short excerpt from the blog post...",
    "url": "posts/post1.html"
  },
  {
    "title": "Second Post",
    "date": "February 1, 2023",
    "excerpt": "Another example blog post excerpt...",
    "url": "posts/post2.html"
  }
  // Add more posts here
]

CSS

/* Added to styles.css */
.pagination {
  display: flex;
  justify-content: center;
  gap: 10px;
  margin: 2rem 0;
}

.pagination button {
  background: #333;
  color: white;
  border: none;
  padding: 0.5rem 1rem;
  cursor: pointer;
}

.pagination button.active {
  background: #555;
}

.pagination button:disabled {
  background: #999;
  cursor: not-allowed;
}

Key Takeaways

  • Displays only 5 posts per page.
  • Uses JavaScript to calculate page numbers automatically.
  • Loads post data from a JSON file.
  • Improves user navigation and content organization.
  • Works well for static blogs hosted online.

What Is Blog Pagination?

Blog pagination is a navigation method that divides a large collection of articles into multiple pages. Instead of showing every post on a single page, content is split into smaller sections for better readability.

Popular content management systems such as WordPress use pagination by default. The same concept can also be implemented manually using HTML, CSS, JavaScript, and JSON data structures.

How Does This Pagination System Work?

The JavaScript code defines a constant called POSTS_PER_PAGE with a value of 5. This determines how many articles appear on each page.

When the page loads, JavaScript fetches data from posts.json, calculates the current page number from the URL parameter, and selects only the relevant posts using the slice() method.

After the posts are displayed, the script automatically generates page navigation buttons, including Newer and Older controls, allowing readers to browse through available content.

What Are the Advantages of This Pagination Method?

  • Improves page organization.
  • Reduces visual clutter.
  • Creates a cleaner browsing experience.
  • Scales well as the number of articles increases.
  • Requires no server-side programming.

Because the solution relies on native browser APIs such as Fetch API and URLSearchParams, it remains lightweight while providing functionality commonly found in larger blogging platforms.

What Are the Limitations?

Limitation Description
Page Reload Changing pages triggers a full reload.
Large JSON Files Performance may decrease if thousands of posts are stored in one file.
No SEO URLs Uses query parameters instead of dedicated archive URLs.
Client-Side Rendering Pagination is generated in the browser.

How Does It Compare with Server-Side Pagination?

Feature Client-Side Pagination Server-Side Pagination
Setup Complexity Simple Moderate
Hosting Cost Low Higher
Performance with Large Data Moderate Better
Static Hosting Support Excellent Limited
Maintenance Easy More Complex

What Tips Can Improve This Pagination Feature?

  • Add First and Last page buttons.
  • Implement smooth transitions without reloading the page.
  • Sort posts by publication date automatically.
  • Add previous and next icons using Font Awesome.
  • Generate SEO-friendly archive pages when possible.
  • Split very large post collections into multiple JSON files.

FAQ

How many posts are displayed per page?

The current configuration shows five posts per page through the POSTS_PER_PAGE constant.

Can I display more than five posts?

Yes. Change the value of POSTS_PER_PAGE to any number that fits your design and usability requirements.

Does this work on GitHub Pages?

Yes. Because the solution uses HTML, CSS, JavaScript, and JSON, it works well on GitHub Pages and other static hosting providers.

Can pagination work without JSON?

Yes, but JSON makes content management easier because all post metadata is stored in a centralized file.

Is this pagination mobile-friendly?

Yes. The flexbox-based CSS layout allows the pagination controls to adapt well across different screen sizes.

Conclusion

This pagination implementation provides a practical way to organize growing blog content without requiring a backend system. By combining HTML, CSS, JavaScript, and JSON, static websites can deliver a cleaner reading experience while maintaining fast deployment on platforms such as GitHub Pages.