Stand with Ukraine 🇺🇦
Eleventy
The possum is Eleventy’s mascot

Eleventy Documentation

Menu

Pagination Jump to heading

Pagination allows you to iterate over a data set and create multiple files from a single template. The input data can be in the form of an array or object defined in your frontmatter or in global data, or you can paginate a collection to make an easily digestible list of your posts.

Expand for Contents

Paging an Array Jump to heading

To iterate over a data set and create pages for individual chunks of data, use pagination. Enable in your template’s front matter by adding the pagination key.

Consider the following template, which will result in two pages being created, each of which will display two items from testdata:

View this example in: Liquid Nunjucks 11ty.js Handlebars
Filename paged.liquid
---
pagination:
data: testdata
size: 2
testdata:
- item1
- item2
- item3
- item4
---
<ol>
{%- for item in pagination.items %}
<li>{{ item }}</li>
{% endfor -%}
</ol>

If the above file were named paged.liquid, it would create two pages in your output folder: _site/paged/index.html and _site/paged/1/index.html. These output paths are configurable with permalink (see below).

Filename paged.njk
---
pagination:
data: testdata
size: 2
testdata:
- item1
- item2
- item3
- item4
---
<ol>
{%- for item in pagination.items %}
<li>{{ item }}</li>
{% endfor -%}
</ol>

If the above file were named paged.njk, it would create two pages in your output folder: _site/paged/index.html and _site/paged/1/index.html. These output paths are configurable with permalink (see below).

Filename paged.11ty.js
exports.data = {
pagination: {
data: "testdata",
size: 2
},
testdata: [
"item1",
"item2",
"item3",
"item4"
]
};

exports.render = function(data) {
return `<ol>
${data.pagination.items.map(function(item) {
return `<li>${item}</li>`;
}).join("")
}

</ol>
`
;
};

If the above file were named paged.11ty.js, it would create two pages in your output folder: _site/paged/index.html and _site/paged/1/index.html. These output paths are configurable with permalink (see below).

This example has not yet been added—you can swap to another template language above! Or maybe you want to contribute it? Edit this page

We enable pagination and then give it a dataset with the data key. We control the number of items in each chunk with size. The pagination data variable will be populated with what you need to create each template. Here’s what’s in pagination:

Syntax JavaScript Object
{
items: [], // Array of current page’s chunk of data
pageNumber: 0, // current page number, 0 indexed

// Cool URLs
hrefs: [], // Array of all page hrefs (in order)
href: {
next: "…", // put inside <a href="">Next Page</a>
previous: "…", // put inside <a href="">Previous Page</a>
first: "…",
last: "…",
},

pages: [], // Array of all chunks of paginated data (in order)
page: {
next: {}, // Next page’s chunk of data
previous: {}, // Previous page’s chunk of data
first: {},
last: {}},
}
}
Expand to see all of the extra stuff in the pagination object that you probably don’t need any more but it’s still in there for backwards compatibility.

In addition to the pagination object entries documented above, it also has:

Syntax JavaScript Object
{
data: "…", // the original string key to the dataset
size: 1, // page chunk sizes

// Cool URLs
// Use pagination.href.next, pagination.href.previous, et al instead.
nextPageHref: "…", // put inside <a href="">Next Page</a>
previousPageHref: "…", // put inside <a href="">Previous Page</a>
firstPageHref: "…",
lastPageHref: "…",

// Uncool URLs
// These include index.html file names, use `hrefs` instead
links: [], // Array of all page links (in order)

// Deprecated things:
// nextPageLink
// previousPageLink
// firstPageLink
// lastPageLink
// pageLinks (alias to `links`)
}

Learn how to create a list of links to every paginated page on a pagination template with a full Pagination Navigation tutorial.

Paging an Object Jump to heading

All of the examples thus far have paged Array data. Eleventy does allow paging objects too. Objects are resolved to pagination arrays using either the Object.keys or Object.values JavaScript functions. Consider the following templates:

View this example in: Liquid Nunjucks 11ty.js Handlebars
Syntax Liquid
---
pagination:
data: testdata
size: 1
testdata:
itemkey1: itemvalue1
itemkey2: itemvalue2
itemkey3: itemvalue3
---
<ol>
{%- for item in pagination.items %}
<li>{{ item }}={{testdata[item] }}</li>
{% endfor -%}
</ol>
Syntax Nunjucks
---
pagination:
data: testdata
size: 1
testdata:
itemkey1: itemvalue1
itemkey2: itemvalue2
itemkey3: itemvalue3
---
<ol>
{%- for item in pagination.items %}
<li>{{ item }}={{testdata[item] }}</li>
{% endfor -%}
</ol>

This example has not yet been added—you can swap to another template language above! Or maybe you want to contribute it? Edit this page

This example has not yet been added—you can swap to another template language above! Or maybe you want to contribute it? Edit this page

In this example, we would get 3 pages that each print a key/value pair from testdata. The paged items hold the object keys:

Syntax JavaScript Object
[
[ "itemkey1" ], // pagination.items[0] holds the object key
[ "itemkey2" ],
[ "itemkey3" ]
]

You can use these keys to get access to the original value: testdata[ pagination.items[0] ].

If you’d like the pagination to iterate over the values instead of the keys (using Object.values instead of Object.keys), add resolve: values to your pagination front matter:

Syntax YAML Front Matter
---
pagination:
data: testdata
size: 1
resolve: values
testdata:
itemkey1: itemvalue1
itemkey2: itemvalue2
itemkey3: itemvalue3

---

This resolves to:

Syntax JavaScript Object
[
[ "itemvalue1" ], // pagination.items[0] holds the object value
[ "itemvalue2" ],
[ "itemvalue3" ]
]

Paginate a global or local data file Jump to heading

Read more about Template Data Files. The only change here is that you point your data pagination key to the global or local data instead of data in the front matter. For example, consider the following globalDataSet.json file in your global data directory.

Syntax JavaScript Object
{
"myData": [
"item1",
"item2",
"item3",
"item4"
]
}

Your front matter would look like this:

View this example in: Liquid Nunjucks 11ty.js Handlebars
Syntax Liquid
---
pagination:
data: globalDataSet.myData
size: 1
---
<ol>
{%- for item in pagination.items %}
<li>{{ item }}</li>
{% endfor -%}
</ol>
Syntax Nunjucks
---
pagination:
data: globalDataSet.myData
size: 1
---
<ol>
{%- for item in pagination.items %}
<li>{{ item }}</li>
{% endfor -%}
</ol>

This example has not yet been added—you can swap to another template language above! Or maybe you want to contribute it? Edit this page

This example has not yet been added—you can swap to another template language above! Or maybe you want to contribute it? Edit this page

Normally, front matter does not support template syntax, but permalink does, enabling parametric URLs via pagination variables. Here’s an example of a permalink using the pagination page number:

Syntax YAML Front Matter using Liquid, Nunjucks
---
permalink: "different/page-{{ pagination.pageNumber }}/index.html"
---

Writes to _site/different/page-0/index.html, _site/different/page-1/index.html, et cetera.

That means Nunjucks will also let you start your page numbers with 1 instead of 0, by just adding 1 here:

Syntax YAML Front Matter using Nunjucks
---
permalink: "different/page-{{ pagination.pageNumber + 1 }}/index.html"
---

Writes to _site/different/page-1/index.html, _site/different/page-2/index.html, et cetera.

You can even use template logic here too:

---
permalink: "different/{% if pagination.pageNumber > 0 %}page-{{ pagination.pageNumber + 1 }}/{% endif %}index.html"
---

Writes to _site/different/index.html, _site/different/page-2/index.html, et cetera.

Note that the above example works in Nunjucks but {{ pagination.pageNumber + 1 }} is not supported in Liquid. Use {{ pagination.pageNumber | plus: 1 }} instead.

You can do more advanced things like this:

Syntax YAML Front Matter using Liquid, Nunjucks
---
pagination:
data: testdata
size: 1
testdata:
- My Item
permalink: "different/{{ pagination.items[0] | slug }}/index.html"

---

Using a universal slug filter (transforms My Item to my-item), this outputs: _site/different/my-item/index.html.

Aliasing to a different variable Jump to heading

Ok, so pagination.items[0] is ugly. We provide an option to alias this to something different.

View this example in: Liquid Nunjucks 11ty.js Handlebars
Syntax Liquid
---
pagination:
data: testdata
size: 1
alias: wonder
testdata:
- Item1
- Item2
permalink: "different/{{ wonder | slug }}/index.html"
---
You can use the alias in your content too {{ wonder }}.
Syntax Nunjucks
---
pagination:
data: testdata
size: 1
alias: wonder
testdata:
- Item1
- Item2
permalink: "different/{{ wonder | slug }}/index.html"
---
You can use the alias in your content too {{ wonder }}.

This example has not yet been added—you can swap to another template language above! Or maybe you want to contribute it? Edit this page

This example has not yet been added—you can swap to another template language above! Or maybe you want to contribute it? Edit this page

This writes to _site/different/item1/index.html and _site/different/item2/index.html.

Note that page is a reserved word so you cannot use alias: page. Read about Eleventy’s reserved data names in Eleventy Supplied Data.

If your chunk size is greater than 1, the alias will be an array instead of a single value.

View this example in: Liquid Nunjucks 11ty.js Handlebars
Syntax Liquid
---
pagination:
data: testdata
size: 2
alias: wonder
testdata:
- Item1
- Item2
- Item3
- Item4
permalink: "different/{{ wonder[0] | slug }}/index.html"
---
You can use the alias in your content too {{ wonder[0] }}.
Syntax Nunjucks
---
pagination:
data: testdata
size: 2
alias: wonder
testdata:
- Item1
- Item2
- Item3
- Item4
permalink: "different/{{ wonder[0] | slug }}/index.html"
---
You can use the alias in your content too {{ wonder[0] }}.

This example has not yet been added—you can swap to another template language above! Or maybe you want to contribute it? Edit this page

This example has not yet been added—you can swap to another template language above! Or maybe you want to contribute it? Edit this page

This writes to _site/different/item1/index.html and _site/different/item3/index.html.

Paging a Collection Jump to heading

If you’d like to make a paginated list of all of your blog posts (any content with the tag post on it), use something like the following template to iterate over a specific collection:

View this example in: Liquid Nunjucks 11ty.js Handlebars
Syntax Liquid
---
title: My Posts
pagination:
data: collections.post
size: 6
alias: posts
---

<ol>
{% for post in posts %}
<li><a href="{{ post.url }}">{{ post.data.title }}</a></li>
{% endfor %}
</ol>
Syntax Nunjucks
---
title: My Posts
pagination:
data: collections.post
size: 6
alias: posts
---

<ol>
{% for post in posts %}
<li><a href="{{ post.url }}">{{ post.data.title }}</a></li>
{% endfor %}
</ol>

This example has not yet been added—you can swap to another template language above! Or maybe you want to contribute it? Edit this page

This example has not yet been added—you can swap to another template language above! Or maybe you want to contribute it? Edit this page

The above generates a list of links but you could do a lot more. See what’s available in the Collection documentation (specifically templateContent). If you’d like to use this to automatically generate Tag pages for your content, please read Quick Tip #004—Create Tag Pages for your Blog.

Generating an Empty Results Page Jump to heading

Coming soon in v2.0.0-canary.10

By default, if the specified data set is empty, Eleventy will not render any pages. Use generatePageOnEmptyData: true to generate one pagination output with an empty chunk [] of items.

Syntax Liquid, Nunjucks
---
title: Available Products
pagination:
data: collections.available
size: 6
generatePageOnEmptyData: true

---

Modifying the Data Set prior to Pagination Jump to heading

Reverse the Data Jump to heading

Use reverse: true.

---
pagination:
data: testdata
size: 2
reverse: true
testdata:
- item1
- item2
- item3
- item4

---

Paginates to:

[
["item4", "item3"],
["item2", "item1"],
]

(More discussion at Issue #194)

As an aside, this could also be achieved in a more verbose way using the Collection API. This could also be done using the new before callback .

Filtering Values Jump to heading

Use the filter pagination property to remove values from paginated data.

Syntax YAML Front Matter
---
pagination:
data: testdata
size: 1
filter:
- item3
testdata:
item1: itemvalue1
item2: itemvalue2
item3: itemvalue3

---

Paginates to:

Syntax JavaScript Object
[
[ "item1" ],
[ "item2" ],
]

This will work the same with paginated arrays or with resolve: values for paginated objects.

Syntax YAML Front Matter
---
pagination:
data: testdata
size: 1
resolve: values
filter:
- itemvalue3
testdata:
item1: itemvalue1
item2: itemvalue2
item3: itemvalue3

---

Paginates to:

Syntax JavaScript Object
[
[ "itemvalue1" ],
[ "itemvalue2" ],
]

The before Callback Jump to heading

The most powerful tool to change the data. Use this callback to modify, filter, or otherwise change the pagination data however you see fit before pagination occurs.

---js
{
pagination: {
data: "testdata",
size: 2,
before: function(paginationData, fullData) {
// `fullData` is new in v1.0.1 and contains the full Data Cascade thus far

return paginationData.map(entry => `${entry} with a suffix`);
}
},
testdata: [
"item1",
"item2",
"item3",
"item4"
]
}
---
<!-- the rest of the template -->

The above will iterate over a data set containing: ["item1 with a suffix", "item2 with a suffix", "item3 with a suffix", "item4 with a suffix"].

You can do anything in this before callback. Maybe a custom .sort(), .filter(), .map() to remap the entries, .slice() to paginate only a subset of the data, etc!

Use JavaScript Template Functions here Jump to heading

Coming soon in v2.0.0-canary.16JavaScript Template Functions (which are also populated by universal filters and shortcodes) are available in the before callback.

// …
before: function() {
let slug = this.slugify("My title.");
// use Universal filters or shortcodes too…
},
// …

Order of Operations Jump to heading

If you use more than one of these data set modification features, here’s the order in which they operate:

Add All Pagination Pages to Collections Jump to heading

By default, any tags listed in a paginated template will only add the very first page to the appropriate collection.

Consider the following pagination template:

Filename my-page.md
---
tags:
- myCollection
pagination:
data: testdata
size: 2
testdata:
- item1
- item2
- item3
- item4
---

This means that collections.myCollection will have only the first page added to the collection array (_site/my-page/index.html). However, if you’d like to add all the pagination pages to the collections, use addAllPagesToCollections: true to the pagination front matter options like so:

Filename my-page.md
---
tags:
- myCollection
pagination:
data: testdata
size: 2
addAllPagesToCollections: true
testdata:
- item1
- item2
- item3
- item4
---

Now collections.myCollection will have both output pages in the collection array (_site/my-page/index.html and _site/my-page/1/index.html).

Full Pagination Option List Jump to heading


Other pages in Working with Templates:


Related Docs