Stop refinementList sorting hits upon selection


Is it possible to select multiple refinementList items and then ‘submit’ them all at once without the results being filtered as I select the?

Hello Brendan!

You can achieve this by using connectors. What you want here is to customize the rendering so that when you click on items, it doesn’t refine right away, but adds refinement values to a list. Then, when clicking on your custom “Submit” button, you iterate on that list and send every value to InstantSearch.

Here’s an example using InstantSearch.js v3: instantsearch.js-app - CodeSandbox

Note that this is a naive implementation. The refine method takes values but either refines or unrefines, depending on whether the value is already refined. For example, if you refine on “Apple”, then re-refine on “Apple”, it will remove the refinement on Apple. Make sure you take this into account when building your UI.



1 Like

Thanks Sarah! Does this work in the same of refinementLists in that if I have 4 lists I need to make 4 custom widgets? Or can I just make one custom list and init it 4 times in the addWidgets method?

Hi @brendan.betheldo, you could use the same connector multiple times as shown in this example: instantsearch.js-app - CodeSandbox.

Note that I moved the “Refine” button to be generated on its own in the index.html, rather than being generated in customRefinementList. This is so that only one is created. Nonetheless, all customRefinementLists are still listening for a click on that element to refine.

Hope this helps!

1 Like

Hi @maria.schreiber, that’s excellent and absolutely helps. Do you think this would cause issues if I had the default, click to refine on desktop and then the select multiple options and submit them to refine on mobile?

Sorry, I’m not sure I understand the difference between the desktop and mobile implementation.

Do you mean you would have an out of the box implementation (each selection refines results) on desktop, but use the custom implementation (wait for submit button) on mobile? If so, I think that sounds totally fine! (And in fact how I have seen UX in a few different places.)

Hi @maria.schreiber, yes that’s exactly what I mean. Thanks @sarah.dayan and @maria.schreiber for the great help!

1 Like


I have a follow up bug with this post that I’d like help with. If I need to make another post let me know.

In the this sandbox instantsearch.js-app - CodeSandbox. I have the search filtering when I select some of them then click ‘refine’ but if I move the declaration of my array valuesToRefine outside of the renderRefinementList method after each value is refined they’re pushed into my first refinementList for some reason.

The reason I need the array declared outside the render method is so I can have other widgets push values into it.

I don’t think it’s a scope issue because everything works fine until the widgets reload.


Hi Brendan!

When you’re moving valuesToRefine outside of the render function, you’re basically sharing the same array of refinements in every refinement list that you instantiate. When you click on them, you’re simply toggling the bold style on it, so that’s why it seems to work fine. However, when you hit “Apply” (which executes the refine function), all refinement lists take that array as input and update themselves. This is why you’re seeing your refinements “move” to the first list: notice that they all have a count of 0, because they don’t exist in that list.

If you need to update the list of values to refine on from outside of the component, then you may need to access and interact with the search state. You can do this by building your own custom widget.

Hi @sarah.dayan, thanks for your reply. I’ll read into the state documentation more and see what I can rig up.

This approach leads to multiple intermediate renderings of the widget, you can see it in the console of the sandbox:

Is there a way to toggle multiple facet values from within connector to avoid multiple search requests and renderings? Maybe, through the helper…

Hi @anantakrishna.kem

If I was bothered by the extra queries and renderings, I would look into creating a custom widget. The helper would be exposed rather than package inside a refine function, and therefore you have the flexibility of forging your request and call .search() when you’re ready to update the state and fire the query.

    render({ helper }) {
      document.querySelector('#custom-widget').innerHTML = `
        <h3>Custom Widget</h3>
          <label> <input type="radio" name="xxx" value="2-3"> 2-3 </label>

        .querySelector('#custom-widget input[value="2-3')
        .addEventListener('change', () => {
            .addDisjunctiveFacetRefinement('rating', '3')
            .addDisjunctiveFacetRefinement('rating', '2')

I’ve changed your sample to show you.

I hope this helps.

Thank you very much, you’ve confirmed my guess that I need to dig deeper and use helper inside a custom widget. Will give it a try.