pagination({
container: string | HTMLElement,
// Optional parameters
showFirst: boolean,
showPrevious: boolean,
showNext: boolean,
showLast: boolean,
padding: number,
totalPages: number,
scrollTo: string | HTMLElement | boolean,
templates: object,
cssClasses: object,
});
import { pagination } from 'instantsearch.js/es/widgets';
See live example
The pagination
widget displays a pagination system which lets users change the current page of search results.
Examples
pagination({
container: "#pagination",
});
Options
container
string | HTMLElement
required
The CSS Selector or HTMLElement
to insert the widget into.pagination({
container: '#pagination',
});
Whether to display the first page link.pagination({
// ...
showFirst: false,
});
Whether to display the previous page link.pagination({
// ...
showPrevious: false,
});
Whether to display the next page link.pagination({
// ...
showNext: false,
});
Whether to display the last page link.pagination({
// ...
showLast: false,
});
The number of pages to display on each side of the current page.pagination({
// ...
padding: 2,
});
The maximum number of pages to browse.pagination({
// ...
totalPages: 2,
});
scrollTo
string | HTMLElement | boolean
default:"body"
Where to scroll after a click. Set to false
to disable.pagination({
// ...
scrollTo: 'header',
});
The templates to use for the widget.pagination({
// ...
templates: {
// ...
},
});
The CSS classes you can override:
root
. The root element of the widget.
noRefinementRoot
. The root container without results.
list
. The list of results.
item
. The item in the list of results.
firstPageItem
. The first item.
lastPageItem
. The last item.
previousPageItem
. The previous item.
nextPageItem
. The next item.
pageItem
. The page items.
selectedItem
. The selected item.
disabledItem
. The disabled item.
link
. The link elements.
pagination({
// ...
cssClasses: {
root: "MyCustomPagination",
list: ["MyCustomPaginationList", "MyCustomPaginationList--subclass"],
},
});
Templates
You can customize parts of a widget’s UI using the Templates API.
Each template includes an html
function,
which you can use as a tagged template.
This function safely renders templates as HTML strings and works directly in the browser—no build step required.
For details, see Templating your UI.
The html
function is available in InstantSearch.js version 4.46.0 or later.
The template for the first page.pagination({
// ...
templates: {
first: '«',
},
});
The template for the previous page.pagination({
// ...
templates: {
previous: '‹',
},
});
The template for the next page.pagination({
// ...
templates: {
next: '›',
},
});
The template for the last page.pagination({
// ...
templates: {
last: '»',
},
});
HTML output
<div class="ais-Pagination">
<ul class="ais-Pagination-list">
<li
class="ais-Pagination-item ais-Pagination-item--firstPage ais-Pagination-item--disabled"
>
<span class="ais-Pagination-link" aria-label="First">‹‹</span>
</li>
<li
class="ais-Pagination-item ais-Pagination-item--previousPage ais-Pagination-item--disabled"
>
<span class="ais-Pagination-link" aria-label="Previous">‹</span>
</li>
<li class="ais-Pagination-item ais-Pagination-item--selected">
<a class="ais-Pagination-link" href="#">1</a>
</li>
<li class="ais-Pagination-item ais-Pagination-item--page">
<a class="ais-Pagination-link" href="#">2</a>
</li>
<li class="ais-Pagination-item ais-Pagination-item--page">
<a class="ais-Pagination-link" href="#">3</a>
</li>
<li class="ais-Pagination-item">
<a class="ais-Pagination-link" href="#">4</a>
</li>
<li class="ais-Pagination-item ais-Pagination-item--nextPage">
<a class="ais-Pagination-link" aria-label="Next" href="#">›</a>
</li>
<li class="ais-Pagination-item ais-Pagination-item--lastPage">
<a class="ais-Pagination-link" aria-label="Last" href="#">››</a>
</li>
</ul>
</div>
If you want to create your own UI of the pagination
widget, you can use connectors.
To use connectPagination
, you can import it with the declaration relevant to how you installed InstantSearch.js.
import { connectPagination } from 'instantsearch.js/es/connectors';
Then it’s a 3-step process:
// 1. Create a render function
const renderPagination = (renderOptions, isFirstRender) => {
// Rendering logic
};
// 2. Create the custom widget
const customPagination = connectPagination(renderPagination);
// 3. Instantiate
search.addWidgets([
customPagination({
// instance params
}),
]);
Create a render function
This rendering function is called before the first search (init
lifecycle step)
and each time results come back from Algolia (render
lifecycle step).
const renderPagination = (renderOptions, isFirstRender) => {
const {
pages,
currentRefinement,
nbHits,
nbPages,
isFirstPage,
isLastPage,
canRefine,
refine,
createURL,
widgetParams,
} = renderOptions;
if (isFirstRender) {
// Do some initial rendering and bind events
}
// Render the widget
};
If SEO is important for your search page, ensure that your custom HTML is optimized for search engines:
- Use
<a>
tags with href
attributes to allow search engine bots to follow links.
- Use semantic HTML and include structured data when relevant.
For more guidance, see the SEO checklist.
Rendering options
The pages relevant to the current situation and padding.const renderPagination = (renderOptions, isFirstRender) => {
const { pages } = renderOptions;
document.querySelector('#pagination').innerHTML = `
<ul>
${pages
.map(
page => `
<li>
<a href="#">${page + 1}</a>
</li>
`
)
.join('')}
</ul>
`;
};
The number of the page currently displayed.const renderPagination = (renderOptions, isFirstRender) => {
const { pages, currentRefinement } = renderOptions;
document.querySelector("#pagination").innerHTML = `
<ul>
${pages
.map(
(page) => `
<li>
<a
href="#"
style="font-weight: ${currentRefinement === page ? "bold" : ""}"
>
${page + 1}
</a>
</li>
`,
)
.join("")}
</ul>
`;
};
The number of hits computed for the last query (can be approximate).const renderPagination = (renderOptions, isFirstRender) => {
const { currentRefinement, nbPages, nbHits } = renderOptions;
document.querySelector("#pagination").innerHTML = ` <span>
${currentRefinement + 1} of ${nbPages} page(s) for ${nbHits} hit(s)
</span>
`;
};
The number of pages for the result set.const renderPagination = (renderOptions, isFirstRender) => {
const { currentRefinement, nbPages, nbHits } = renderOptions;
document.querySelector("#pagination").innerHTML = `
<span>
${currentRefinement + 1} of ${nbPages} page(s) for ${nbHits} hit(s)
</span>
`;
};
Whether the current page is the first page.const renderPagination = (renderOptions, isFirstRender) => {
const { pages, isFirstPage, isLastPage } = renderOptions;
document.querySelector("#pagination").innerHTML = `
<ul>
${
!isFirstPage
? `
<li>
<a href="#">Previous</a>
</li>
`
: ""
}
${pages
.map(
(page) => `
<li>
<a href="#">
${page + 1}
</a>
</li>
`,
)
.join("")}
${
!isLastPage
? `
<li>
<a href="#">Next</a>
</li>
`
: ""
}
</ul>
`;
};
Whether the current page is the last page.const renderPagination = (renderOptions, isFirstRender) => {
const { pages, isFirstPage, isLastPage } = renderOptions;
document.querySelector("#pagination").innerHTML = `
<ul>
${
!isFirstPage
? `
<li>
<a href="#">Previous</a>
</li>
`
: ""
}
${pages
.map(
(page) => `
<li>
<a href="#">
${page + 1}
</a>
</li>
`,
)
.join("")}
${
!isLastPage
? `
<li>
<a href="#">Next</a>
</li>
`
: ""
}
</ul>
`;
};
Indicates if search state can be refined.const renderPagination = (renderOptions, isFirstRender) => {
const { canRefine } = renderOptions;
if (!canRefine) {
document.querySelector("#pagination").innerHTML = "";
return;
}
};
Sets the current page and triggers a search.const renderPagination = (renderOptions, isFirstRender) => {
const { pages, currentRefinement, refine } = renderOptions;
const container = document.querySelector("#pagination");
container.innerHTML = `
<ul>
${pages
.map(
(page) => `
<li>
<a
href="#"
data-value="${page}"
style="font-weight: ${currentRefinement === page ? "bold" : ""}"
>
${page + 1}
</a>
</li>
`,
)
.join("")}
</ul>
`;
[...container.querySelectorAll("a")].forEach((element) => {
element.addEventListener("click", (event) => {
event.preventDefault();
refine(event.currentTarget.dataset.value);
});
});
};
Generates a URL for the next state.
The number is the page to generate the URL for.const renderPagination = (renderOptions, isFirstRender) => {
const { pages, createURL } = renderOptions;
document.querySelector("#pagination").innerHTML = `
<ul>
${pages
.map(
(page) => `
<li>
<a href="${createURL(page)}">
${page + 1}
</a>
</li>
`,
)
.join("")}
</ul>
`;
};
All original widget options forwarded to the render function.const renderPagination = (renderOptions, isFirstRender) => {
const { widgetParams } = renderOptions;
widgetParams.container.innerHTML = "...";
};
// ...
search.addWidgets([
customPagination({
container: document.querySelector("#pagination"),
}),
]);
First, create your custom widgets using a rendering function.
Then, instantiate them with parameters.
There are two kinds of parameters you can pass:
- Instance parameters. Predefined options that configure Algolia’s behavior.
- Custom parameters. Parameters you define to make the widget reusable and adaptable.
Inside the renderFunction
, both instance and custom parameters are accessible through connector.widgetParams
.
const customPagination = connectPagination(renderPagination);
search.addWidgets([customPagination({ totalPages: number, padding: number })]);
Instance options
The total number of pages to browse.customPagination({
totalPages: 4,
});
The padding of pages to show around the current pagecustomPagination({
padding: 2,
});
Full example
<div id="pagination"></div>