API Reference / InstantSearch.js Widgets / hitsPerPage
Widget signature
instantsearch.widgets.hitsPerPage({
  container: string|HTMLElement,
  items: object[],
  // Optional parameters
  cssClasses: object,
  transformItems: function,
});

About this widget # A

The hitsPerPage widget displays a dropdown menu to let the user change the number of displayed hits.

If you only want to configure the number of hits per page without displaying a widget, you can use the configure widget with the hitsPerPage search parameter.

Examples # A

1
2
3
4
5
6
7
instantsearch.widgets.hitsPerPage({
  container: '#hits-per-page',
  items: [
    { label: '8 hits per page', value: 8, default: true },
    { label: '16 hits per page', value: 16 },
  ],
});

Options # A

container #
type: string|HTMLElement
Required

The CSS Selector or HTMLElement to insert the widget into.

1
2
3
4
instantsearch.widgets.hitsPerPage({
  // ...
  container: '#hits-per-page',
});
items #
type: object[]
Required

The list of available options, with each item:

  • label: string: the label to display in the option.
  • value: number: the number of hits to display per page.
  • default: boolean: the default hits per page on first search.
1
2
3
4
5
6
7
instantsearch.widgets.hitsPerPage({
  // ...
  items: [
    { label: '8 hits per page', value: 8, default: true },
    { label: '16 hits per page', value: 16 },
  ],
});
cssClasses #
type: object
default: {}
Optional

The CSS classes to override.

  • root: the root element of the widget.
  • select: the select element.
  • option: the option elements of the select.
1
2
3
4
5
6
7
8
9
10
instantsearch.widgets.hitsPerPage({
  // ...
  cssClasses: {
    root: 'MyCustomHitsPerPage',
    select: [
      'MyCustomHitsPerPageSelect',
      'MyCustomHitsPerPageSelect--subclass',
    ],
  },
});
transformItems #
type: function
default: items => items
Optional

Receives the items, and is called before displaying them. Should return a new array with the same shape as the original array. Useful for mapping over the items to transform, and remove or reorder them.

1
2
3
4
5
6
7
8
9
instantsearch.widgets.hitsPerPage({
  // ...
  transformItems(items) {
    return items.map(item => ({
      ...item,
      label: item.label.toUpperCase(),
    }));
  },
});

HTML output# A

1
2
3
4
5
6
<div class="ais-HitsPerPage">
  <select class="ais-HitsPerPage-select">
    <option class="ais-HitsPerPage-option" value="8">8 per page</option>
    <option class="ais-HitsPerPage-option" value="16">16 per page</option>
  </select>
</div>

Customize the UI - connectHitsPerPage# A

If you want to create your own UI of the hitsPerPage widget, you can use connectors.

It’s a 3-step process:

// 1. Create a render function
const renderHitsPerPage = (renderOptions, isFirstRender) => {
  // Rendering logic
};

// 2. Create the custom widget
const customHitsPerPage = instantsearch.connectors.connectHitsPerPage(
  renderHitsPerPage
);

// 3. Instantiate
search.addWidgets([
  customHitsPerPage({
    // 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 renderHitsPerPage = (renderOptions, isFirstRender) => {
  const {
    object[] items,
    boolean hasNoResults,
    function refine,
    object widgetParams,
  } = renderOptions;

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

  // Render the widget
}

Rendering options #

items #
type: object[]

The list of items the widget can display, with each item:

  • label: string: the label to display in the option.
  • value: number: the number of hits to display per page.
  • isRefined: boolean: indicates if the item is the current refined value.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const renderHitsPerPage = (renderOptions, isFirstRender) => {
  const { items } = renderOptions;

  document.querySelector('#hits-per-page').innerHTML = `
    <select>
      ${items
        .map(
          item => `
            <option
              value="${item.value}"
              ${item.isRefined ? 'selected' : ''}
            >
              ${item.label}
            </option>
          `
        )
        .join('')}
    </select>
  `;
};
hasNoResults #
type: boolean

Indicates whether or not the search has results.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const renderHitsPerPage = (renderOptions, isFirstRender) => {
  const { items, hasNoResults } = renderOptions;

  document.querySelector('#hits-per-page').innerHTML = `
    <select ${hasNoResults ? 'disabled' : ''}>
      ${items
        .map(
          item => `
            <option
              value="${item.value}"
              ${item.isRefined ? 'selected' : ''}
            >
              ${item.label}
            </option>
          `
        )
        .join('')}
    </select>
  `;
};
refine #
type: function

Sets the number of hits per 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
const renderHitsPerPage = (renderOptions, isFirstRender) => {
  const { items, refine } = renderOptions;
  const container = document.querySelector('#hits-per-page');

  if (isFirstRender) {
    const select = document.createElement('select');

    select.addEventListener('change', event => {
      refine(event.target.value);
    });

    container.appendChild(select);
  }

  container.querySelector('select').innerHTML = `
    ${items
      .map(
        item => `
          <option
            value="${item.value}"
            ${item.isRefined ? 'selected' : ''}
          >
            ${item.label}
          </option>
        `
      )
      .join('')}
  `;
};
widgetParams #
type: object

All original widget options forwarded to the render function.

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

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

// ...

search.addWidgets([
  customHitsPerPage({
    container: document.querySelector('#hits-per-page'),
  })
]);

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 customHitsPerPage = instantsearch.connectors.connectHitsPerPage(
  renderHitsPerPage
);

search.addWidgets([
  customHitsPerPage({
    object[] items,
    function transformItems,
  })
]);

Instance options #

items #
type: object[]
Required

The list of available options, with each item:

  • label: string: the label to display in the option.
  • value: number: the number of hits to display per page.
  • default: boolean: the default hits per page on first search.
1
2
3
4
5
6
customHitsPerPage({
  items: [
    { label: '8 hits per page', value: 8, default: true },
    { label: '16 hits per page', value: 16 },
  ],
});
transformItems #
type: function
default: items => items
Optional

Receives the items, and is called before displaying them. Should return a new array with the same shape as the original array. Useful for mapping over the items to transform, and remove or reorder them.

1
2
3
4
5
6
7
8
9
customHitsPerPage({
  // ...
  transformItems(items) {
    return items.map(item => ({
      ...item,
      label: item.label.toUpperCase(),
    }));
  },
});

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
// Create the render function
const renderHitsPerPage = (renderOptions, isFirstRender) => {
  const { items, hasNoResults, refine, widgetParams } = renderOptions;

  if (isFirstRender) {
    const select = document.createElement('select');

    select.addEventListener('change', event => {
      refine(event.target.value);
    });

    widgetParams.container.appendChild(select);
  }

  const select = widgetParams.container.querySelector('select');

  select.disabled = hasNoResults;

  select.innerHTML = `
    ${items
      .map(
        item => `
          <option
            value="${item.value}"
            ${item.isRefined ? 'selected' : ''}
          >
            ${item.label}
          </option>
        `
      )
      .join('')}
  `;
};

// Create the custom widget
const customHitsPerPage = instantsearch.connectors.connectHitsPerPage(
  renderHitsPerPage
);

// Instantiate the custom widget
search.addWidgets([
  customHitsPerPage({
    container: document.querySelector('#hits-per-page'),
    items: [
      { label: '8 hits per page', value: 8, default: true },
      { label: '16 hits per page', value: 16 },
    ],
  })
]);

Did you find this page helpful?