Where to Discuss?

Local Group

Preface

Goal: A Simple Pagination.

Hugo Pagination: Combined Animation


1: Prepare

Pagination can be set in config.toml

Paginate     = 7

In layout we are going to use

{{ $paginator := .Paginate .Site.Pages }}

Since we only show specific page kind named post, we should filter the pages using where.

{{ $paginator := .Paginate (where .Site.Pages "Type" "post") }}

While debugging, or development process, we can do this to override sitewide paginate configuration. Here we use 5 articles for each pagination page.

{{ $paginator := .Paginate (where .Site.Pages "Type" "post") 5 }}

This is a very helpful trick for me.


2: Preview: General

This is what we want to achieve in this tutorial.

Hugo Pagination: Simple Positioning Indicator

HTML Preview

The HTML that we want to achieve in this article, is similar as below.

<ul class="pagination justify-content-center">
  <li class="page-item disabled">
    <span class="page-link">First</span>
  </li>
  <li class="page-item disabled">
    <span class="page-link">Previous</span>
  </li>
   <li class="page-item disabled">
    <span class="page-link">Page: 1 of 3</span>
  </li>
  <li class="page-item">
    <a class="page-link" href="/pages/page/2/" rel="next">Next</a>
  </li>
  <li class="page-item">
    <a class="page-link" href="/pages/page/3/" rel="last">Last</a>
  </li>
</ul>

We will achieve this with Hugo code.


3: Layout

Change our previous blog list

  • themes/tutor-05/layouts/archives/list.html.
  {{ $posts := where .Site.Pages "Type" "post" }}
  <section id="archive">
  <div class="post-list">
    {{ range $posts }}
      {{ partial "summary-blog-list.html" . }}
    {{ end }}
  </div>
  </section>

to use paginator

  {{ $paginator := .Paginate (where .Site.Pages "Type" "post") }}
  {{ partial "pagination-simple.html" (dict "p" $paginator) }}
  <section id="archive">
  <div class="post-list">
    {{ range $paginator.Pages }}
      {{ partial "summary-blog-list.html" . }}
    {{ end }}
  </div>
  </section>

Layout: List

The complete file is here below:

{{ define "main" }}
<main role="main" 
      class="container-fluid m-3 m-sm-0 p-3
             bg-light rounded border border-dark shadow-hover">
  <header>
    <h4>{{ .Title | default .Site.Title }}</h4>
  </header>

  <article>
    {{ .Content }}
  </article>

  {{ $paginator := .Paginate (where .Site.Pages "Type" "post") }}
  {{ partial "pagination-simple.html" (dict "p" $paginator) }}
  <section id="archive">
  <div class="post-list">
    {{ range $paginator.Pages }}
      {{ partial "summary-blog-list.html" . }}
    {{ end }}
  </div>
  </section>
</main>
{{ end }}

Dictionary

In order to pass variable from list layout to pagination partial, we utilize dictionary: (dict “p” $paginator).

  {{ $paginator := .Paginate (where .Site.Pages "Type" "post") }}
  {{ partial "pagination-simple.html" (dict "p" $paginator) }}

4: Navigation: Previous and Next

No need to show any pagination navigation, if we what we have is only one page. Hence our minimal pagination logic would be:

<nav aria-label="Page navigation">

  {{ if gt .p.TotalPages 1 }}
  <ul class="pagination justify-content-center">
  ...
  </ul>
  {{ end }}
</nav>

Of course this is not enough. Our minimal pagination should show something.

Partial: Pagination Simple

<nav aria-label="Page navigation">

  {{ if gt .p.TotalPages 1 }}
  <ul class="pagination justify-content-center">

    <!-- Previous Page. -->
    {{ if .p.HasPrev }}
      <li class="page-item">
        <a class="page-link" href="{{ .p.Prev.URL }}"
           rel="prev">Previous</a>
      </li>
    {{ else }}
      <li class="page-item disabled">
        <span class="page-link">Previous</span>
      </li>
    {{ end }}

    <!-- Next Page. -->
    {{ if .p.HasNext }}
      <li class="page-item">
        <a class="page-link" href="{{ .p.Next.URL }}"
           rel="next">Next</a>
      </li>
    {{ else }}
      <li class="page-item disabled">
        <span class="page-link">Next</span>
      </li>
    {{ end }}

  </ul>
  {{ end }}

</nav>

Browser: Pagination Preview

Hugo Pagination: Simple Previous Next

How does it works ?

This code above rely on

  • Previous Page: if .HasPrev, and

  • Next Page: if .HasNext.

This should be self explanatory.

Stylesheet: Bootstrap Class

Bootstrap specific class are these below

  • ul: pagination

  • li: page-item

  • a, span: page-link

  • li: disabled


5: Navigation: First and Last

Consider also add first page and last page.

<nav aria-label="Page navigation">

  {{ if gt .p.TotalPages 1 }}
  <ul class="pagination justify-content-center">

    <!-- First Page. -->
    {{ if not (eq .p.PageNumber 1) }}
      <li class="page-item">
        <a class="page-link" href="{{ .p.First.URL }}"
           rel="first">First</a>
      </li>
    {{ else }}
      <li class="page-item disabled">
        <span class="page-link">First</span>
      </li>
    {{ end }}

    ...

    <!-- Last Page. -->
    {{ if not (eq .p.PageNumber .p.TotalPages) }}
      <li class="page-item">
        <a class="page-link" href="{{ .p.Last.URL }}"
           rel="last">Last</a>
      </li>
    {{ else }}
      <li class="page-item disabled">
        <span class="page-link">Last</span>
      </li>
    {{ end }}
  </ul>
  {{ end }}

</nav>

Browser: Pagination Preview

Hugo Pagination: Simple First Last

How does it works ?

Since there is no equivalent for .HasPrev and .HasNext to show first page and last page, we utilize:

  • First Page: .PageNumber == 1.

  • Last Page: .PageNumber == .TotalPages.


6: Active Page Indicator

And also the pagination positioning in between, in the middle of those.

<nav aria-label="Page navigation">

  {{ if gt .p.TotalPages 1 }}
  <ul class="pagination justify-content-center">
    ...

    <!-- Indicator Number. -->
    <li class="page-item">
      <span class="page-link">
        Page: {{ .p.PageNumber }} of {{ .p.TotalPages }}</span>
    </li>

    ...
  </ul>
  {{ end }}

</nav>

Browser: Pagination Preview

Hugo Pagination: Simple Positioning Indicator

How does it works ?

This just show:

Page: {{ .p.PageNumber }} of {{ .p.TotalPages }}

7: Summary

Complete code is here below:

<nav aria-label="Page navigation">

  {{ if gt .p.TotalPages 1 }}
  <ul class="pagination justify-content-center">

    <!-- First Page. -->
    {{ if not (eq .p.PageNumber 1) }}
      <li class="page-item">
        <a class="page-link" href="{{ .p.First.URL }}" 
           rel="first">First</a>
      </li>
    {{ else }}
      <li class="page-item disabled">
      <span class="page-link">First</span>
    {{ end }}

    <!-- Previous Page. -->
    {{ if .p.HasPrev }}
      <li class="page-item">
        <a class="page-link" href="{{ .p.Prev.URL }}" 
           rel="prev">Previous</a>
      </li>
    {{ else }}
      <li class="page-item disabled">
        <span class="page-link">Previous</span>
      </li>
    {{ end }}

    <!-- Indicator Number. -->
    <li class="page-item disabled">
      <span class="page-link">
        Page: {{ .p.PageNumber }} of {{ .p.TotalPages }}</span>
    </li>

    <!-- Next Page. -->
    {{ if .p.HasNext }}
      <li class="page-item">
        <a class="page-link" href="{{ .p.Next.URL }}" 
           rel="next">Next</a>
      </li>
    {{ else }}
      <li class="page-item disabled">
        <span class="page-link">Next</span>
      </li>
    {{ end }}

    <!-- Last Page. -->
    {{ if not (eq .p.PageNumber .p.TotalPages) }}
      <li class="page-item">
        <a class="page-link" href="{{ .p.Last.URL }}" 
           rel="last">Last</a>
      </li>
    {{ else }}
      <li class="page-item disabled">
        <span class="page-link">Last</span>
      </li>
    {{ end }}
  </ul>
  {{ end }}

</nav>

What is Next ?

Just like this adorable kitten, you may feel excited. Consider resume our tutorial.

adorable kitten

There are, some interesting topic about Pagination in Hugo. Consider continue reading [ Hugo - Pagination - Number ].

Thank you for reading.