API Reference / InstantSearch.js / pagination
Signature
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
1
import { pagination } from 'instantsearch.js/es/widgets';

About this widget

The pagination widget displays a pagination system allowing the user to change the current page.

The Algolia search engine limits paginating to 1,000 hits per page.

Examples

1
2
3
pagination({
  container: '#pagination',
});

Options

container
type: string|HTMLElement
Required

The CSS Selector or HTMLElement to insert the widget into.

1
2
3
pagination({
  container: '#pagination',
});
showFirst
type: boolean
default: true
Optional

Whether to display the first page link.

1
2
3
4
pagination({
  // ...
  showFirst: false,
});
showPrevious
type: boolean
default: true
Optional

Whether to display the previous page link.

1
2
3
4
pagination({
  // ...
  showPrevious: false,
});
showNext
type: boolean
default: true
Optional

Whether to display the next page link.

1
2
3
4
pagination({
  // ...
  showNext: false,
});
showLast
type: boolean
default: true
Optional

Whether to display the last page link.

1
2
3
4
pagination({
  // ...
  showLast: false,
});
padding
type: number
default: 3
Optional

The number of pages to display on each side of the current page.

1
2
3
4
pagination({
  // ...
  padding: 2,
});
totalPages
type: number
Optional

The maximum number of pages to browse.

1
2
3
4
pagination({
  // ...
  totalPages: 2,
});
scrollTo
type: string|HTMLElement|boolean
default: body
Optional

Where to scroll after a click. Set to false to disable.

1
2
3
4
pagination({
  // ...
  scrollTo: 'header',
});
templates
type: object

The templates to use for the widget.

1
2
3
4
5
6
pagination({
  // ...
  templates: {
    // ...
  },
});
cssClasses
type: object
default: {}

The CSS classes to 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.
1
2
3
4
5
6
7
8
9
10
pagination({
  // ...
  cssClasses: {
    root: 'MyCustomPagination',
    list: [
      'MyCustomPaginationList',
      'MyCustomPaginationList--subclass',
    ],
  },
});

Templates

You can customize parts of the widget’s UI using the Templates API.

Every template provides an html function you can use as a tagged template. Using html lets you safely provide templates as an HTML string. It works directly in the browser without a build step. See Templating your UI for more information.

The html function is available starting from v4.46.0.

first
type: string|function
Optional

The template for the first page.

1
2
3
4
5
6
pagination({
  // ...
  templates: {
    first: '«',
  },
});
previous
type: string|function
Optional

The template for the previous page.

1
2
3
4
5
6
pagination({
  // ...
  templates: {
    previous: '',
  },
});
next
type: string|function
Optional

The template for the next page.

1
2
3
4
5
6
pagination({
  // ...
  templates: {
    next: '',
  },
});
last
type: string|function
Optional

The template for the last page.

1
2
3
4
5
6
pagination({
  // ...
  templates: {
    last: '»',
  },
});

HTML output

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<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>

Customize the UI with connectPagination

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.

1
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 {
    number[] pages,
    number currentRefinement,
    number nbHits,
    number nbPages,
    boolean isFirstPage,
    boolean isLastPage,
    boolean canRefine,
    function refine,
    function createURL,
    function widgetParams,
  } = renderOptions;

  if (isFirstRender) {
    // Do some initial rendering and bind events
  }

  // Render the widget
}

If SEO is critical to your search page, your custom HTML markup needs to be parsable:

  • use plain <a> tags with href attributes for search engines bots to follow them,
  • use semantic markup with structured data when relevant, and test it.

Refer to our SEO checklist for building SEO-ready search experiences.

Rendering options

pages
type: number[]

The pages relevant to the current situation and padding.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const renderPagination = (renderOptions, isFirstRender) => {
  const { pages } = renderOptions;

  document.querySelector('#pagination').innerHTML = `
    <ul>
      ${pages
        .map(
          page => `
            <li>
              <a href="#">${page + 1}</a>
            </li>
          `
        )
        .join('')}
    </ul>
  `;
};
currentRefinement
type: number

The number of the page currently displayed.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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>
  `;
};
nbHits
type: number

The number of hits computed for the last query (can be approximate).

1
2
3
4
5
6
7
8
9
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>
  `;
};
nbPages
type: number

The number of pages for the result set.

1
2
3
4
5
6
7
8
9
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>
  `;
};
isFirstPage
type: boolean

Whether the current page is the first page.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
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>
  `;
};
isLastPage
type: boolean

Whether the current page is the last page.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
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>
  `;
};
canRefine
type: boolean
Required

Indicates if search state can be refined.

1
2
3
4
5
6
7
8
const renderPagination = (renderOptions, isFirstRender) => {
  const { canRefine } = renderOptions;

  if (!canRefine) {
    document.querySelector('#pagination').innerHTML = '';
    return;
  }
};
refine
type: function

Sets the current page and triggers a search.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
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);
    });
  });
};
createURL
type: function

Generates a URL for the next state. The number is the page to generate the URL for.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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>
  `;
};
widgetParams
type: function

All original widget options forwarded to the render function.

1
2
3
4
5
6
7
8
9
10
11
12
13
const renderPagination = (renderOptions, isFirstRender) => {
  const { widgetParams } = renderOptions;

  widgetParams.container.innerHTML = '...';
};

// ...

search.addWidgets([
  customPagination({
    container: document.querySelector('#pagination'),
  })
]);

Create and instantiate the custom widget

We first create custom widgets from our rendering function, then we instantiate them. When doing that, there are two types of parameters you can give:

  • Instance parameters: they are predefined parameters that you can use to configure the behavior of Algolia.
  • Your own parameters: to make the custom widget generic.

Both instance and custom parameters are available in connector.widgetParams, inside the renderFunction.

const customPagination = connectPagination(
  renderPagination
);

search.addWidgets([
  customPagination({
    totalPages: number,
    padding: number,
  })
]);

Instance options

totalPages
type: number
Optional

The total number of pages to browse.

1
2
3
customPagination({
  totalPages: 4,
});
padding
type: number
default: 3
Optional

The padding of pages to show around the current page

1
2
3
customPagination({
  padding: 2,
});

Full example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
// Create the render function
const renderPagination = (renderOptions, isFirstRender) => {
  const {
    pages,
    currentRefinement,
    nbPages,
    isFirstPage,
    isLastPage,
    refine,
    createURL,
  } = renderOptions;

  const container = document.querySelector('#pagination');

  container.innerHTML = `
    <ul>
      ${
        !isFirstPage
          ? `
            <li>
              <a
                href="${createURL(0)}"
                data-value="${0}"
              >
                First
              </a>
            </li>
            <li>
              <a
                href="${createURL(currentRefinement - 1)}"
                data-value="${currentRefinement - 1}"
              >
                Previous
              </a>
            </li>
            `
          : ''
      }
      ${pages
        .map(
          page => `
            <li>
              <a
                href="${createURL(page)}"
                data-value="${page}"
                style="font-weight: ${currentRefinement === page ? 'bold' : ''}"
              >
                ${page + 1}
              </a>
            </li>
          `
        )
        .join('')}
        ${
          !isLastPage
            ? `
              <li>
                <a
                  href="${createURL(currentRefinement + 1)}"
                  data-value="${currentRefinement + 1}"
                >
                  Next
                </a>
              </li>
              <li>
                <a
                  href="${createURL(nbPages - 1)}"
                  data-value="${nbPages - 1}"
                >
                  Last
                </a>
              </li>
              `
            : ''
        }
    </ul>
  `;

  [...container.querySelectorAll('a')].forEach(element => {
    element.addEventListener('click', event => {
      event.preventDefault();
      refine(event.currentTarget.dataset.value);
    });
  });
};

// Create the custom widget
const customPagination = connectPagination(
  renderPagination
);

// Instantiate the custom widget
search.addWidgets([
  customPagination({
    container: document.querySelector('#pagination'),
  })
]);
Did you find this page helpful?