API Reference / InstantSearch.js Widgets / dynamicWidgets
Widget signature
instantsearch.widgets.dynamicWidgets({
  container: string|HTMLElement,
  widgets: function[],
  // optional parameters
  transformItems: function,
  fallbackWidget: function,
});

About this widget

DynamicWidgets is a widget that displays matching widgets, based on by the corresponding settings of the index and may be altered by a query rule. You can configure the facet merchandising through the corresponding index setting.

Requirements

You must set the attributes for faceting attributesForFaceting and configure the facet order, either using the dashboard or using attributesForFaceting and renderingContent respectively with the API.

Due to the nature of this widget, the matching widgets will mount after the first network request. To avoid a second network request, you can use a configure to make sure that second request is caught by the cache.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
search.addWidgets([
  instantsearch.widgets.configure({
    facets: ['*'],
    // the highest value you could mount in "limit"
    maxValuesPerFacet: 10,
  }),
  instantsearch.widgets.dynamicWidgets({
    container: '#dynamic-widgets',
    fallbackWidget: ({ container, attribute }) =>
      instantsearch.widgets.menu({ container, attribute, limit: 10 }),
    widgets: [
      container =>
        instantsearch.widgets.hierarchicalMenu({
          limit: 10,
          attributes: [
            'hierarchicalCategories.lvl0',
            'hierarchicalCategories.lvl1',
          ],
        }),
    ],
  }),
]);

Examples

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
instantsearch.widgets.dynamicWidgets({
  container: '#dynamic-widgets',
  widgets: [
    container =>
      instantsearch.widgets.refinementList({ container, attribute: 'brand' }),
    container =>
      instantsearch.widgets.hierarchicalMenu({
        container,
        attributes: [
          'hierarchicalCategories.lvl0',
          'hierarchicalCategories.lvl1',
        ],
      }),
  ],
  fallbackWidget: ({ container, attribute }) =>
    instantsearch.widgets.panel({ templates: { header: attribute } })(
      instantsearch.widgets.menu
    )({ container, attribute }),
});

Options

container
type: string|HTMLElement
Required

The CSS Selector of the DOM element inside which the widget is inserted.

1
2
3
4
instantsearch.widgets.dynamicWidgets({
  // ...
  container: '#dynamic-widgets',
});
widgets
type: Array<(container: HTMLElement) => Widget>
Required

A list of creator functions for all widgets you want to conditionally display. Each creator will receive a container and is expected to return a widget. The creator can also return custom widgets created with connectors.

Note that the returned widget needs to have an “attribute” or “attributes” argument, as this will be used to determine which widgets to render in which order.

1
2
3
4
5
6
7
instantsearch.widgets.dynamicWidgets({
  // ...
  widgets: [
    container =>
      instantsearch.widgets.refinementList({ container, attribute: 'brand' }),
  ],
});
fallbackWidget
type: (args: { attribute: string, container: HTMLElement }) => Widget
Optional

A creator function that is called for every attribute you want to conditionally display. The creator will receive a container and attribute and is expected to return a widget. The creator can also return custom widgets created with connectors.

1
2
3
4
5
instantsearch.widgets.dynamicWidgets({
  // ...
  fallbackWidget: ({ container, attribute }) =>
    instantsearch.widgets.refinementList({ container, attribute }),
});
transformItems
type: function
Optional

A function to transform the attributes to render, or using a different source to determine the attributes to render.

1
2
3
4
5
6
instantsearch.widgets.dynamicWidgets({
  // ...
  transformItems(items, { results }) {
    return items;
  },
});

Customize the UI - connectDynamicWidgets

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

It’s a 3-step process:

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

// 2. Create the custom widget
const customDynamicWidgets = instantsearch.connectors.connectDynamicWidgets(
  renderDynamicWidgets
);

// 3. Instantiate
search.addWidgets([
  customDynamicWidgets({
    // 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 renderDynamicWidgets = (renderOptions, isFirstRender) => {
  const {
    string[] attributesToRender,
  } = renderOptions;

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

  // Render the widget
}

Rendering options

attributesToRender
type: string[]

The list of refinement values to display returned from the Algolia API.

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

  document.querySelector('#dynamic-widgets').innerHTML = `
    <ul>
      ${attributesToRender
        .map(
          attribute => `
            <li>
              ${attribute}
            </li>`
        )
        .join('')}
    </ul>
  `;
};
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
14
const renderDynamicWidgets = (renderOptions, isFirstRender) => {
  const { widgetParams } = renderOptions;

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

// ...

search.addWidgets([
  customDynamicWidgets({
    // ...
    container: document.querySelector('#dynamic-widgets'),
  })
]);

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 customDynamicWidgets = instantsearch.connectors.connectDynamicWidgets(
  renderDynamicWidgets
);

search.addWidgets([
  customDynamicWidgets({
    widgets: string[],
    // Optional parameters
    transformItems: function,
  })
]);

Instance options

widgets
type: object[]
Required

The widgets to dynamically be added to the parent index. Note that you manually will have change their DOM position.

1
2
3
customDynamicWidgets({
  widgets: [refinementList(), customWidget()],
});
transformItems
type: function
Optional

A function to transform the attributes to render, or using a different source to determine the attributes to render.

1
2
3
4
5
6
customDynamicWidgets({
  // ...
  transformItems(items, { results }) {
    return items;
  },
});

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
// 0. Create a mapping between widgets and their attribute
const widgets = {
  brand: {
    widget: refinementList({container: this.container}),
    container: document.createElement('div')
  },
  custom: {
    widget: customWidget({container: this.container}),
    container: document.createElement('div')
  }
};

// 1. Create a render function
const renderDynamicWidgets = (renderOptions, isFirstRender) => {
  const {
    attributesToRender,
    widgetParams,
  } = renderOptions;

  if (isFirstRender) {
    const ul = document.createElement('ul');
    widgetParams.container.appendChild(ul);
  }

  const ul = widgetParams.container.querySelector('ul');
  ul.innerHTML = '';

  attributesToRender.forEach(attribute => {
    const container = widgets[attribute].container;
    ul.appendChild(container);
  });
};

// 2. Create the custom widget
const customDynamicWidgets = instantsearch.connectors.connectDynamicWidgets(
  renderDynamicWidgets
);

// 3. Instantiate
search.addWidgets([
  customDynamicWidgets({
    container: document.querySelector('#dynamic-widgets'),
    widgets: Object.values(widgets).map(({widget}) => widget),
  })
]);
Did you find this page helpful?