Pagination
Split large content lists into multiple pages.
Configuration
Site-Level Defaults
Set default pagination behavior in config.toml:
[pagination]
enabled = false
per_page = 10
| Key | Type | Default | Description |
|---|---|---|---|
| enabled | bool | false | Enable pagination globally |
| per_page | int | 10 | Default items per page |
Section Pagination
Enable in section front matter:
+++
title = "Blog"
paginate = 10
paginate_path = "page"
+++
| Field | Type | Default | Description |
|---|---|---|---|
| paginate | int | — | Items per page |
| paginate_path | string | "page" | URL pattern for pages |
Generated URLs
For a section at /blog/:
| Page | URL |
|---|---|
| 1 | /blog/ |
| 2 | /blog/page/2/ |
| 3 | /blog/page/3/ |
With paginate_path = "p":
| Page | URL |
|---|---|
| 1 | /blog/ |
| 2 | /blog/p/2/ |
| 3 | /blog/p/3/ |
Template Variables
pagination
Pre-rendered pagination HTML:
{{ pagination | safe }}
paginator
Pagination object for custom rendering:
| Property | Type | Description |
|---|---|---|
| paginator.paginate_by | Int | Items per page |
| paginator.base_url | String | Base URL for pagination |
| paginator.number_pagers | Int | Total number of pagers (pages) |
| paginator.first | String | URL to first pager |
| paginator.last | String | URL to last pager |
| paginator.previous | String? | URL to previous pager |
| paginator.next | String? | URL to next pager |
| paginator.pages | Array | Array of pages for the current pager |
| paginator.current_index | Int | Current pager index (1-indexed) |
| paginator.total_pages | Int | Total number of pages |
pagination_obj
Structured pagination object with individual fields for building fully custom pagination markup:
| Property | Type | Description |
|---|---|---|
| pagination_obj.html | String | Pre-rendered pagination HTML (same as pagination) |
| pagination_obj.current_page | Int | Current page number (1-indexed) |
| pagination_obj.total_pages | Int | Total number of pages |
| pagination_obj.per_page | Int | Items per page |
| pagination_obj.total_items | Int | Total number of items across all pages |
| pagination_obj.has_previous | Bool | Whether a previous page exists |
| pagination_obj.has_next | Bool | Whether a next page exists |
| pagination_obj.previous_url | String | URL to previous page (empty if none) |
| pagination_obj.next_url | String | URL to next page (empty if none) |
| pagination_obj.first_url | String | URL to first page |
| pagination_obj.last_url | String | URL to last page |
{% if pagination_obj.has_previous %}
<a href="{{ pagination_obj.previous_url }}">← Newer</a>
{% endif %}
<span>Page {{ pagination_obj.current_page }} of {{ pagination_obj.total_pages }}</span>
{% if pagination_obj.has_next %}
<a href="{{ pagination_obj.next_url }}">Older →</a>
{% endif %}
Template Examples
Simple Navigation
Use the pre-rendered pagination variable:
{% extends "base.html" %}
{% block content %}
<h1>{{ section.title }}</h1>
<ul>
{% for p in section.pages %}
<li><a href="{{ p.url }}">{{ p.title }}</a></li>
{% endfor %}
</ul>
{{ pagination | safe }}
{% endblock %}
Custom Pagination
Build your own pagination UI:
{% if paginator.number_pagers > 1 %}
<nav class="pagination">
{% if paginator.previous %}
<a href="{{ paginator.previous }}" class="prev">← Previous</a>
{% endif %}
<span class="current">
Page {{ paginator.current_index }} of {{ paginator.number_pagers }}
</span>
{% if paginator.next %}
<a href="{{ paginator.next }}" class="next">Next →</a>
{% endif %}
</nav>
{% endif %}
Full Pagination with Page Numbers
{% if paginator.number_pagers > 1 %}
<nav class="pagination">
{# First page #}
{% if paginator.current_index > 1 %}
<a href="{{ paginator.first }}">« First</a>
{% endif %}
{# Previous #}
{% if paginator.previous %}
<a href="{{ paginator.previous }}">‹ Prev</a>
{% endif %}
{# Current #}
<span class="current">{{ paginator.current_index }} / {{ paginator.number_pagers }}</span>
{# Next #}
{% if paginator.next %}
<a href="{{ paginator.next }}">Next ›</a>
{% endif %}
{# Last page #}
{% if paginator.current_index < paginator.number_pagers %}
<a href="{{ paginator.last }}">Last »</a>
{% endif %}
</nav>
{% endif %}
Ellipsis for Large Page Counts
When there are more than 7 pages, the built-in pagination navigation automatically inserts ellipsis (...) to keep the UI compact. A sliding window of 5 page numbers around the current page is shown, with the first and last pages always visible.
For example, on page 5 of 20:
« Prev 1 ... 3 4 [5] 6 7 ... 20 Next »
SEO Links
Hwaro generates <link rel="prev"> and <link rel="next"> tags for paginated pages. Include them in your <head>:
<head>
{{ pagination_seo_links | safe }}
</head>
Output:
<link rel="prev" href="https://example.com/blog/page/2/">
<link rel="next" href="https://example.com/blog/page/4/">
Taxonomy Pagination
Taxonomies also support pagination in config.toml:
[[taxonomies]]
name = "tags"
paginate = 20
CSS Example
.pagination {
display: flex;
gap: 1rem;
justify-content: center;
margin: 2rem 0;
}
.pagination a {
padding: 0.5rem 1rem;
border: 1px solid #ddd;
text-decoration: none;
}
.pagination a:hover {
background: #f0f0f0;
}
.pagination .current {
padding: 0.5rem 1rem;
font-weight: bold;
}
See Also
- Sections — Section configuration
- Taxonomies — Taxonomy pagination
- Data Model — Section variables