Working with Pagination

On this page

Aether provides built-in pagination support for content listings in taxonomy pages (categories/tags) and special custom templates. Pagination is automatically handled by the system and provides comprehensive navigation data.

Where Pagination is Available

Pagination is available in the following contexts:

  • Category pages (/category/:slug) - Lists posts in a category
  • Tag pages (/tag/:slug) - Lists posts with a tag
  • Special custom templates - Templates with slugs: blog, archive, articles, news, search
  • Static site generation - All paginated content during SSG

Pagination Object Structure

The pagination object contains the following properties:

Property Type Description Example
currentPage Number Current page number (1-based) 2
totalPages Number Total number of pages 5
totalItems Number Total number of items across all pages 47
pageSize Number Items displayed per page 10
prevPage Number/null Previous page number (null if first page) 1
nextPage Number/null Next page number (null if last page) 3
urls Object Complete URL structure for navigation See structure below

URLs Object Structure

The urls object provides ready-to-use URLs for all pagination navigation:

{
  first: "/category/tech",           // First page URL
  prev: "/category/tech",            // Previous page URL (null if first page)
  current: "/category/tech/page/2",  // Current page URL
  next: "/category/tech/page/3",     // Next page URL (null if last page)
  last: "/category/tech/page/5"      // Last page URL
}

URL Generation Rules

  • Dynamic sites: URLs use query parameters (e.g., ?page=2)
  • Static sites: URLs use clean paths (e.g., /category/tech/page/2/)
  • First page: Always uses the base URL without page suffix
  • Custom pages: Don't include content type in path (e.g., /blog/page/2)

Template Implementation Examples

Basic Pagination Navigation

{{#if pagination}}
<nav class="pagination" aria-label="Pagination Navigation">
    {{#if pagination.prevPage}}
    <a href="{{pagination.urls.prev}}" class="pagination-prev" rel="prev">&laquo; Previous</a>
    {{/if}}

    <span class="pagination-info">
        Page {{pagination.currentPage}} of {{pagination.totalPages}} ({{pagination.totalItems}} total items)
    </span>

    {{#if pagination.nextPage}}
    <a href="{{pagination.urls.next}}" class="pagination-next" rel="next">Next &raquo;</a>
    {{/if}}
</nav>
{{/if}}

Advanced Pagination with Page Numbers

{{#if pagination}}
<nav class="pagination" aria-label="Page Navigation">
    <!-- First page link -->
    {{#not pagination.currentPage == 1}}
    <a href="{{pagination.urls.first}}" class="pagination-first">First</a>
    {{/not}}

    <!-- Previous page link -->
    {{#if pagination.prevPage}}
    <a href="{{pagination.urls.prev}}" class="pagination-prev" rel="prev">&laquo;</a>
    {{/if}}

    <!-- Current page indicator -->
    <span class="pagination-current" aria-current="page">{{pagination.currentPage}}</span>

    <!-- Next page link -->
    {{#if pagination.nextPage}}
    <a href="{{pagination.urls.next}}" class="pagination-next" rel="next">&raquo;</a>
    {{/if}}

    <!-- Last page link -->
    {{#not pagination.currentPage == pagination.totalPages}}
    <a href="{{pagination.urls.last}}" class="pagination-last">Last</a>
    {{/not}}
</nav>
{{/if}}

Pagination Info Display

{{#if pagination}}
<div class="pagination-info">
    {{#if pagination.totalItems > 0}}
    <!---->
    {{#set startItem = (pagination.currentPage - 1) * pagination.pageSize + 1}}
    <!---->
    {{#set endItem = pagination.currentPage == pagination.totalPages ? pagination.totalItems : pagination.currentPage *
    pagination.pageSize}}
    <!---->
    Showing {{startItem}} to {{endItem}} of {{pagination.totalItems}} results
    <!---->
    {{#else}}
    <!---->
    No results found
    <!---->
    {{/if}}
</div>
{{/if}}

Pagination in Different Contexts

Category/Tag Archives

<!-- Category/Tag template -->
<h1>
    {{#if categoryName}}
    <!---->
    Category: {{categoryName}}
    <!---->
    {{#elseif tagName}} Tag: {{tagName}}
    <!---->
    {{/if}}
</h1>

{{#if posts}}
<div class="posts-grid">
    {{#each posts}}
    <article class="post-card">
        <h2><a href="/post/{{metadata.slug}}">{{metadata.title}}</a></h2>
        <p>{{content}}</p>
    </article>
    {{/each}}
</div>

<!-- Include pagination partial -->
{{#include("components/pagination.html")}}
<!---->
{{#else}}
<p>No posts found in this {{taxonomyType}}.</p>
{{/if}}

Custom Blog Template

<!-- custom/blog.html -->
<h1>{{metadata.title}}</h1>
<div class="blog-content">{{html_content}}</div>

{{#if posts}}
<div class="blog-posts">
    {{#each posts}}
    <article class="blog-post">
        <h2><a href="/post/{{metadata.slug}}">{{metadata.title}}</a></h2>
        {{#if metadata.excerpt}}
        <p class="excerpt">{{metadata.excerpt}}</p>
        {{/if}}
        <div class="post-meta">
            <time datetime="{{metadata.createdAt}}">{{metadata.createdAt | dateFormat("MMMM D, YYYY")}}</time>
            {{#if metadata.author}} by {{metadata.author}} {{/if}}
        </div>
    </article>
    {{/each}}
</div>

<!-- Include pagination partial -->
{{#include("components/pagination.html")}} {{/if}}

CSS Styling Examples

Basic Pagination Styles

.pagination {
    display: flex;
    justify-content: center;
    align-items: center;
    gap: 0.5rem;
    margin: 2rem 0;
    font-family: inherit;
}

.pagination a,
.pagination span {
    padding: 0.5rem 1rem;
    text-decoration: none;
    border: 1px solid #e1e5e9;
    border-radius: 0.25rem;
    color: #495057;
    background-color: #fff;
    transition: all 0.15s ease-in-out;
}

.pagination a:hover {
    background-color: #e9ecef;
    border-color: #adb5bd;
}

.pagination-current {
    background-color: #007bff;
    border-color: #007bff;
    color: #fff;
    font-weight: bold;
}

.pagination-info {
    text-align: center;
    color: #6c757d;
    font-size: 0.875rem;
    margin: 1rem 0;
}

Responsive Pagination

/* Mobile-first pagination */
.pagination {
    flex-wrap: wrap;
    gap: 0.25rem;
}

.pagination-info {
    width: 100%;
    order: -1;
    margin-bottom: 1rem;
}

@media (min-width: 768px) {
    .pagination {
        gap: 0.5rem;
    }

    .pagination-info {
        width: auto;
        order: 0;
        margin-bottom: 0;
    }
}

Performance Notes

  • Pagination data is calculated server-side for optimal performance
  • URLs are pre-generated to avoid template-side calculations
  • Page size is configurable through site settings (postsPerPage)
  • Static site generation creates separate HTML files for each paginated page
  • Large datasets are efficiently handled through database-style offset/limit patterns

Accessibility Considerations

  • Use semantic <nav> elements with aria-label
  • Include rel="prev" and rel="next" attributes for SEO and accessibility
  • Mark current page with aria-current="page"
  • Provide clear pagination context with page counts and totals
  • Ensure keyboard navigation works properly for all pagination links