Our website is made possible by displaying online advertisements to our visitors. Please consider supporting us by disabling your ad blocker.

Add Pagination to Your Eleventy Static Generated Website in Minutes

TwitterFacebookRedditLinkedInHacker News

A few months ago you might remember a tutorial I put out regarding remote caching in Eleventy. In this tutorial titled, Download and Cache YouTube Data in an Eleventy Website with Simple JavaScript, I demonstrated how I was automatically gathering YouTube videos from a playlist on my Poké Trainer Nic channel and publishing them to my Eleventy website.

At the time, this was the best thing since sliced bread for that particular website. Fast forward to now and we’ve got a problem with too many videos loading all at once with a ten hour scroll to reach the bottom. The scroll time is an over exaggeration, but you get the idea that too much content on a single page can become a problem.

This lead me to pagination and showing only a small subset of videos per page.

We’re going to see how to very quickly add pagination to an Eleventy website, something that can be accomplished with a few lines of HTML and a few minutes of your time.

To get a better idea of what we want to accomplish, take a look at the following image:

Eleventy Pagination on Poke Trainer Nic

We want to add all the possible page numbers along with a next page or previous page button.

Let’s set our expectations before proceeding. What we build is not going to look as fancy as what I have because we won’t be focusing on the CSS and design side of things, only the functional. We’re also not going to explore the Eleventy basics and we’re going to assume you have the proper dependencies in place.

The Data for Pagination within Eleventy

Since I’m basing this tutorial on my own personal experiences, we’re going to use video data. However, this tutorial can be used for anything that you want to paginate. For example you could paginate blog posts, e-commerce listings, or something else.

Add a videos.json file to your project’s _data directory with the following JSON:

[
    {
        "title": "Fortnite Trios on Christmas Eve 2021 with the Family",
        "url": "https://www.youtube.com/watch?v=on38FbIpwMg",
        "thumbnail": "https://i.ytimg.com/vi/on38FbIpwMg/mqdefault.jpg"
    },
    {
        "title": "Christmas Pokémon Card Haul 2021, the Celebrations Extravaganza",
        "url": "https://www.youtube.com/watch?v=gmFXMfJRtSo",
        "thumbnail": "https://i.ytimg.com/vi/gmFXMfJRtSo/mqdefault.jpg"
    },
    {
        "title": "Pokémon Sword & Shield Fusion Strike One Pack Magic or Not, Episode 56 #Shorts",
        "url": "https://www.youtube.com/watch?v=0VzGL0rLEMM",
        "thumbnail": "https://i.ytimg.com/vi/0VzGL0rLEMM/mqdefault.jpg"
    },
    {
        "title": "Halo Infinite Ranked Battles on a Wednesday [2021-12-29]",
        "url": "https://www.youtube.com/watch?v=dnDyJ6k1N1A",
        "thumbnail": "https://i.ytimg.com/vi/dnDyJ6k1N1A/mqdefault.jpg"
    },
    {
        "title": "Pokémon TCG Costco Kanto Region Tin Collection",
        "url": "https://www.youtube.com/watch?v=x7Syl6_wArs",
        "thumbnail": "https://i.ytimg.com/vi/x7Syl6_wArs/mqdefault.jpg"
    },
    {
        "title": "Pokémon Sword & Shield Fusion Strike One Pack Magic or Not, Episode 55 #Shorts",
        "url": "https://www.youtube.com/watch?v=10SL4i6ndNk",
        "thumbnail": "https://i.ytimg.com/vi/10SL4i6ndNk/mqdefault.jpg"
    }
]

The above JSON was taken from my previous tutorial and is the output from the caching mechanism that we had set up.

With the data in place, we can proceed to the pagination step.

Adding Pagination to a Nunjucks Page in Eleventy

I used Nunjucks as my template engine for the Poké Trainer Nic website. You may need to make slight adjustments if you’re using a different template engine.

Within a videos.njk file at the root of your Eleventy project, add the following code:

---json
{
    "pagination": {
        "data": "videos",
        "size": 3,
        "alias": "videos"
    }
}
---

<div>
    {% for video in videos %}
        <div>
            <img src="{{ video.thumbnail }}" alt="{{ video.title }}" loading="lazy" />
            <div><a class="text-black" href="{{ video.url }}" target="_blank" rel="noreferrer noopener">{{ video.title }}</a></div>
        </div>
    {% endfor %}
</div>

<div>
    <ul>
        <li>{% if pagination.href.previous %}<a href="{{ pagination.href.previous }}">Prev</a>{% endif %}</li>
        {%- for pageEntry in pagination.pages %}
            <li><a href="{{ pagination.hrefs[ loop.index0 ] }}">{{ loop.index }}</a></li>
        {%- endfor %}
        <li>{% if pagination.href.next %}<a href="{{ pagination.href.next }}">Next</a>{% endif %}</li>
    </ul>
</div>

There are three things worth noting in the above code.

Let’s start with the following section:

{
    "pagination": {
        "data": "videos",
        "size": 3,
        "alias": "videos"
    }
}

We’re saying we want to take the data from the _data/videos.json file, paginate it at three entries per page, and alias it as videos once again. You can alias it to whatever you want.

The next step is to loop through only the items for that particular page.

<div>
    {% for video in videos %}
        <div>
            <img src="{{ video.thumbnail }}" alt="{{ video.title }}" loading="lazy" />
            <div><a class="text-black" href="{{ video.url }}" target="_blank" rel="noreferrer noopener">{{ video.title }}</a></div>
        </div>
    {% endfor %}
</div>

We’re looping through the alias and displaying each item from our data set. The pagination information we defined at the top of our file takes care of what exists in the loop.

Finally we can define how to switch pages.

<div>
    <ul>
        <li>{% if pagination.href.previous %}<a href="{{ pagination.href.previous }}">Prev</a>{% endif %}</li>
        {%- for pageEntry in pagination.pages %}
            <li><a href="{{ pagination.hrefs[ loop.index0 ] }}">{{ loop.index }}</a></li>
        {%- endfor %}
        <li>{% if pagination.href.next %}<a href="{{ pagination.href.next }}">Next</a>{% endif %}</li>
    </ul>
</div>

In the above markup we check to see if there is a previous page. If there is a previous page then we show a link to go back, otherwise we do nothing. Then we add an index to each of the available pages based on our data. Finally we check to see if a next page is available and if it is, then show a link to the next page.

You don’t need to show a previous or next button and you don’t need to show individual numeric indexes. You can mix and match however you want.

If you built and ran your Eleventy website, you’d end up with two pages based on our data set and the pagination number we chose.

If you like how I styled my actual website, I used Tailwind. The class information for what we just saw looks like the following:

<div class="flex flex-wrap flex-row items-start justify-center">
    {% for video in videos %}
        <div class="w-full md:w-1/2 lg:w-1/4 p-0 md:p-3 mb-8 text-center">
            <a href="{{ video.url }}" target="_blank" rel="noreferrer noopener"><img class="w-full mx-auto" src="{{ video.thumbnail }}" alt="{{ video.title }}" loading="lazy" /></a>
            <div class="font-bold"><a class="text-black" href="{{ video.url }}" target="_blank" rel="noreferrer noopener">{{ video.title }}</a></div>
        </div>
    {% endfor %}
</div>

<div class="md:block hidden my-6 text-center">
    <ul class="inline-flex list-none ml-0">
        <li>{% if pagination.href.previous %}<a class="py-3 px-5 text-pokemon-dark-blue transition-colors duration-150 bg-white rounded-l-lg focus:shadow-outline hover:bg-pokemon-light-blue hover:text-white" href="{{ pagination.href.previous }}">Prev</a>{% endif %}</li>
        {%- for pageEntry in pagination.pages %}
            <li><a href="{{ pagination.hrefs[ loop.index0 ] }}"{% if page.url == pagination.hrefs[ loop.index0 ] %} class="py-3 px-5 text-white transition-colors duration-150 bg-pokemon-dark-blue focus:shadow-outline"{% else %} class="py-3 px-5 text-pokemon-dark-blue transition-colors duration-150 bg-white focus:shadow-outline hover:bg-pokemon-light-blue hover:text-white"{% endif %}>{{ loop.index }}</a></li>
        {%- endfor %}
        <li>{% if pagination.href.next %}<a class="py-3 px-5 text-pokemon-dark-blue transition-colors duration-150 bg-white rounded-r-lg focus:shadow-outline hover:bg-pokemon-light-blue hover:text-white" href="{{ pagination.href.next }}">Next</a>{% endif %}</li>
    </ul>
</div>

Some of the classes I used are custom, but you can more or less see what I’ve done in terms of the design.

Conclusion

You just saw how to add simple pagination to your Eleventy static website. The best part of all this is that you don’t need to change your entire website template. Simply adding pagination information in the front-matter and adding a block for navigation will get the job done. Eleventy will take care of the rest.

If you haven’t already, I encourage you to check out my YouTube example. While it wasn’t dependent to follow this tutorial, it could be valuable for your own Eleventy website.

A video version of this tutorial can be found below.

Nic Raboy

Nic Raboy

Nic Raboy is an advocate of modern web and mobile development technologies. He has experience in C#, JavaScript, Golang and a variety of frameworks such as Angular, NativeScript, and Unity. Nic writes about his development experiences related to making web and mobile development easier to understand.