menu
instantsearch.widgets.menu({ container: string|HTMLElement, attribute: string, // Optional parameters limit: number, showMore: boolean, showMoreLimit: number, sortBy: string[]|function, templates: object, cssClasses: object, transformItems: function, });
About this widget # A
The menu
widget displays a menu that lets the user choose a single value for a specific attribute.
Requirements#
The attribute provided to the widget must be in attributes for faceting, either on the dashboard or using attributesForFaceting
with the API.
Examples # A
1
2
3
4
instantsearch.widgets.menu({
container: '#menu',
attribute: 'categories',
});
Options # A
container
# |
type: string|HTMLElement
Required
The CSS Selector of the DOM element inside which the widget is inserted. |
||
Copy
|
|||
attribute
# |
type: string
Required
The name of the attribute in the records. |
||
Copy
|
|||
limit
# |
type: number
default: 10
Optional
How many facet values to retrieve. When you enable the showMore feature, this is the number of facet values to display before clicking the “Show more” button. |
||
Copy
|
|||
showMore
# |
type: boolean
default: false
Optional
Limits the number of results and display a |
||
Copy
|
|||
showMoreLimit
# |
type: number
default: 20
Optional
How many facet values to retrieve when showing more. |
||
Copy
|
|||
sortBy
# |
type: string[]|function
default: Uses facetOrdering if set, ["isRefined", "name:asc"]
Optional
How to sort refinements. Must be one or more of the following strings:
It’s also possible to give a function, which receives items two by two, like JavaScript’s If |
||
Copy
|
|||
templates
# |
type: object
Optional
The templates to use for the widget. |
||
Copy
|
|||
cssClasses
# |
type: object
default: {}
Optional
The CSS classes to override.
|
||
Copy
|
|||
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 transforming, removing, or reordering items. In addition, the full |
||
Copy
|
Templates # A
item
# |
type: string|function
Optional
Item template. It exposes:
|
||
Copy
|
|||
showMoreText
# |
type: string|function
Optional
The template for the “Show more” button text. It exposes:
|
||
Copy
|
HTML output# A
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<div class="ais-Menu">
<div class="ais-Menu-searchBox">
<!-- SearchBox widget here -->
</div>
<ul class="ais-Menu-list">
<li class="ais-Menu-item ais-Menu-item--selected">
<a class="ais-Menu-link" href="#">
<span class="ais-Menu-label">Appliances</span>
<span class="ais-Menu-count">4,306</span>
</a>
</li>
<li class="ais-Menu-item">
<a class="ais-Menu-link" href="#">
<span class="ais-Menu-label">Audio</span>
<span class="ais-Menu-count">1,570</span>
</a>
</li>
</ul>
<button class="ais-Menu-showMore">Show more</button>
</div>
Customize the UI with connectMenu# A
If you want to create your own UI of the menu
widget, you can use connectors.
This connector is also used to build other widgets: MenuSelect
It’s a 3-step process:
// 1. Create a render function
const renderMenu = (renderOptions, isFirstRender) => {
// Rendering logic
};
// 2. Create the custom widget
const customMenu = instantsearch.connectors.connectMenu(
renderMenu
);
// 3. Instantiate
search.addWidgets([
customMenu({
// Widget parameters
})
]);
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 renderMenu = (renderOptions, isFirstRender) => {
const {
object[] items,
boolean canRefine,
function refine,
function sendEvent,
function createURL,
boolean isShowingMore,
boolean canToggleShowMore,
function toggleShowMore,
object 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 withhref
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 #
items
# |
type: object[]
The elements that can be refined for the current search results. With each item:
|
||
Copy
|
|||
canRefine
# |
type: boolean
Required
Indicates if search state can be refined. |
||
Copy
|
|||
refine
# |
type: function
A function to toggle a refinement. |
||
Copy
|
|||
sendEvent
# |
type: (eventType, facetValue) => void
The function to send
|
||
Copy
|
|||
createURL
# |
type: function
default: (item.value) => string
Generates a URL for the corresponding search state. |
||
Copy
|
|||
isShowingMore
# |
type: boolean
Returns |
||
Copy
|
|||
canToggleShowMore
# |
type: boolean
Returns |
||
Copy
|
|||
toggleShowMore
# |
type: function
Toggles the number of displayed values between |
||
Copy
|
|||
widgetParams
# |
type: object
All original widget options forwarded to the render function. |
||
Copy
|
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 customMenu = instantsearch.connectors.connectMenu(
renderMenu
);
search.addWidgets([
customMenu({
attribute: string,
// Optional instance params
limit: number,
showMoreLimit: number,
sortBy: string[]|function,
transformItems: function,
})
]);
Instance options #
attribute
# |
type: string
Required
The name of the attribute for faceting. |
||
Copy
|
|||
limit
# |
type: number
default: 10
Optional
How many facet values to retrieve. When you enable the |
||
Copy
|
|||
showMoreLimit
# |
type: number
default: 10
Optional
How many facet values to retrieve when showing more. |
||
Copy
|
|||
sortBy
# |
type: string[]|function
default: Uses facetOrdering if set, ["isRefined", "name:asc"]
Optional
How to sort refinements. Must be one or more of the following strings:
It’s also possible to give a function, which receives items two by two, like JavaScript’s If |
||
Copy
|
|||
transformItems
# |
type: function
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 transforming, removing, or reordering items. In addition, the full |
||
Copy
|
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
// 1. Create a render function
const renderMenu = (renderOptions, isFirstRender) => {
const {
items,
refine,
createURL,
isShowingMore,
canToggleShowMore,
toggleShowMore,
widgetParams,
} = renderOptions;
if (isFirstRender) {
const ul = document.createElement('ul');
const button = document.createElement('button');
button.textContent = 'Show more';
button.addEventListener('click', () => {
toggleShowMore();
});
widgetParams.container.appendChild(ul);
widgetParams.container.appendChild(button);
}
widgetParams.container.querySelector('ul').innerHTML = items
.map(
item => `
<li>
<a
href="${createURL(item.value)}"
data-value="${item.value}"
style="font-weight: ${item.isRefined ? 'bold' : ''}"
>
${item.label} (${item.count})
</a>
</li>
`
)
.join('');
[...widgetParams.container.querySelectorAll('a')].forEach(element => {
element.addEventListener('click', event => {
event.preventDefault();
refine(event.currentTarget.dataset.value);
});
});
const button = widgetParams.container.querySelector('button');
button.disabled = !canToggleShowMore;
button.textContent = isShowingMore ? 'Show less' : 'Show more';
};
// 2. Create the custom widget
const customMenu = instantsearch.connectors.connectMenu(
renderMenu
);
// 3. Instantiate
search.addWidgets([
customMenu({
container: document.querySelector('#menu'),
attribute: 'categories',
showMoreLimit: 20,
})
]);