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">« 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 »</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">«</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">»</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 witharia-label
- Include
rel="prev"
andrel="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