Salesforce, Python, SQL, & other ways to put your data where you need it

Need event music? 🎸

Live and recorded jazz, pop, and meditative music for your virtual conference / Zoom wedding / yoga class / private party with quality sound and a smooth technical experience

Adding Algolia InstantSearch to my site

03 Jul 2021 🔖 web development jamstack
💬 EN

Table of Contents

Here’s my code

Minimum viable build

I created a file c:\example\algoliaindex.html and double-clicked it to open it in my browser.

To get Algolia working at all, I had to put a DIV into my HTML with an ID that had a distinctive name, such as search-searchbar.

Then, in addition to importing some JavaScript libraries from 3rd parties, I had to put some JavaScript into my codebase that:

  1. Prepared InstantSearch by instantiating it as a variable called search.
  2. Called upon the addWidget() function of search, passing it InstantSearch’s searchBox widget, wiring it up by ID to look for search-searchbar in my DOM (this is also where I configured placeholder text).
  3. Told InstantSearch to go ahead and inject widgets into my DOM with the start() function of search.

Here’s what algoliaindex.html looks like:

<html>

  <head>
    <title>Algolia index experiment</title>
  </head>

  <body>

    <p>Hello, world</p>
    <div id="search-searchbar"></div>
    <p>Well, that was neat</p>

    <!-- Start end-of-page scripts -->

    <!-- Import the basic InstantSearch library -->
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/instantsearch.min.js"></script>

    <!-- Import moment for date parsing -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.20.1/moment.min.js"></script>

    <!-- Make InstantSearch put widgets in the DOM -->
    <script>
      // --- Prep InstantSearch ---
      const search = instantsearch({
        appId: "MY_APP_ID",
        apiKey: "MY_SEARCH_ONLY_API_KEY",
        indexName: "MY_INDEX_NAME",
      });
      // --- Define some custom helpers ---
      // TO DO
      // --- Define the "searchbar" as using the "searchBox" widget
      search.addWidget(
        instantsearch.widgets.searchBox({
          container: "#search-searchbar",
          placeholder: "Search this site...",
          poweredBy: true, // This is required if you're on the free Community plan
          autofocus: false,
        })
      );
      // --- Throw InstantSearch into the DOM ---
      search.start();
    </script>
    <!-- End end-of-page scripts -->

  </body>

</html>

When I refreshed it in my browser, I saw the following lines of content:

  1. “Hello, world”
  2. A “search this site…” box
  3. “Search by Algolia”
  4. A massive magnifying glass
  5. “Well, that was neat”

If I typed “hello” into the search box, I could see my request come in at https://algolia.com/apps/MY_APP_ID/monitoring/logs. When I clicked the latest result and inspected the Request body, its params included the phrase query=hello, so everything’s working great.

Hooray, I have a minimum viable build for my Algolia front-end code! It looks terrible and doesn’t yet display any results on my page, but it appears at all, and it functions.

Search box CSS

Inspecting the page with my browser’s developer tools, I see that Algolia injected a lot into my search-searchbar so that it looks like this in the DOM:

<div id="search-searchbar">
  <div class="ais-search-box">
    <input
      autocapitalize="none"
      autocomplete="off"
      autocorrect="off"
      placeholder="Search this site..."
      role="textbox"
      spellcheck="false"
      type="text"
      value=""
      class="ais-search-box--input"
    />
    <span class="">
      <div class="ais-search-box--powered-by">
        Search by
        <a
          class="ais-search-box--powered-by-link"
          href="https://www.algolia.com/?utm_source=instantsearch.js&amp;utm_medium=website&amp;utm_content=&amp;utm_campaign=poweredby"
          target="_blank"
          >Algolia</a>
      </div>
    </span>
    <span class="ais-search-box--magnifier-wrapper">
      <div class="ais-search-box--magnifier">
        <svg
          xmlns="http://www.w3.org/2000/svg"
          id="sbx-icon-search-13"
          viewBox="0 0 40 40"
          width="100%"
          height="100%"
        >
          <path
            d="M26.804 29.01c-2.832 2.34-6.465 3.746-10.426 3.746C7.333 32.756 0 25.424 0 16.378 0 7.333 7.333 0 16.378 0c9.046 0 16.378 7.333 16.378 16.378 0 3.96-1.406 7.594-3.746 10.426l10.534 10.534c.607.607.61 1.59-.004 2.202-.61.61-1.597.61-2.202.004L26.804 29.01zm-10.426.627c7.323 0 13.26-5.936 13.26-13.26 0-7.32-5.937-13.257-13.26-13.257C9.056 3.12 3.12 9.056 3.12 16.378c0 7.323 5.936 13.26 13.258 13.26z"
            fill-rule="evenodd"
          ></path>
        </svg>
      </div>
    </span>
    <span class="ais-search-box--reset-wrapper" style="display: none">
      <button
        type="reset"
        title="Clear the search query."
        class="ais-search-box--reset"
      >
        <svg
          xmlns="http://www.w3.org/2000/svg"
          viewBox="0 0 20 20"
          width="100%"
          height="100%"
        >
          <path
            d="M8.114 10L.944 2.83 0 1.885 1.886 0l.943.943L10 8.113l7.17-7.17.944-.943L20 1.886l-.943.943-7.17 7.17 7.17 7.17.943.944L18.114 20l-.943-.943-7.17-7.17-7.17 7.17-.944.943L0 18.114l.943-.943L8.113 10z"
            fill-rule="evenodd"
          ></path>
        </svg>
      </button>
    </span>
  </div>
</div>

It looks like I’ll want to consider defining CSS for div.ais-search-box and its sub-elements:

  • input.ais-search-box--input
  • div.ais-search-box--powered-by
    • a.ais-search-box--powered-by-link
  • span.ais-search-box--magnifier-wrapper
    • div.ais-search-box--magnifier
  • span.ais-search-box--reset-wrapper

Rather than mess with all that, let’s see what comes out of the box in Algolia stylesheets – I’ll throw a couple of LINK tags importing InstantSearch CSS libraries after my SCRIPT tags importing the InstantSearch & Moment.js JavaScript libraries.

    ...
    <!-- Import moment for date parsing -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.20.1/moment.min.js"></script>
    <!-- Import some InstantSearch styling -->
    <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/instantsearch.min.css">
    <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/instantsearch-theme-algolia.min.css">
    <!-- Make InstantSearch put widgets in the DOM -->
    ...

That looks much better – the magnifying glass is now inside the search box to the left of “Search this site…” and “Search by Algolia” floats to the bottom right of the search box.

But … do I really like this CSS library? Will it play nicely with Tailwind?

Let’s find out.

  ...
  <head>
    <title>Algolia index experiment</title>
    <link href="https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css" rel="stylesheet">
  </head>
  <body>
    <p>Hello, world</p>
    <div class="w-10 bg-red-500">x</div>
    <div id="search-searchbar" class="w-16 h-8"></div>
    <p>Well, that was neat</p>
    <!-- Start end-of-page scripts -->
    <!-- Import the basic InstantSearch library -->
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/instantsearch.min.js"></script>
    <!-- Import moment for date parsing -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.20.1/moment.min.js"></script>
    <!-- Import some InstantSearch styling -->
    <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/instantsearch.min.css">
    <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/instantsearch-theme-algolia.min.css">
    <!-- Make InstantSearch put widgets in the DOM -->
  ...

When I refreshed this in my browser, I saw the following lines of content:

  1. “Hello, world”
  2. “x” in a red box that’s 2.5rem wide.
  3. A “search this site…” box starting with a magnifying glass that clips its inner hint-text content to make sure that it doesn’t exceed 4rem wide. However, it is definitely overflowing its 2rem height limit.
  4. “Search by Algolia” that is trying to be right-aligned to the search box, but the search box is so narrow that it looks left-aligned on the page, and then it overflows the 4rem limit.
  5. “Well, that was neat” starting right below the 2rem height limit of the element before it, but partially obscured by the searchbox and by “Search by Algolia”.

Adding overflow-hidden to the div#search-searchbar classes clips out the bottom of the searchbox and the “Search by algolia” text altogether, but that’s not quite right.

My conclusion? The searchbox widget’s default styling doesn’t interfere too badly with anything else I might want to do with my theme, as long as I give its container enough height that nothing looks wonky. I’ll just make sure it gets the space it wants. I’m not going to bother to write custom CSS.

V2 to V4 upgrade

It looks like the tutorial I started from was using out-of-date Algolia imports, so I’m going to take a moment to update the imports w/ the modern CDN scripts:

    <!-- Import the basic InstantSearch libraries -->
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/algoliasearch-lite.umd.js" integrity="sha256-EXPXz4W6pQgfYY3yTpnDa3OH8/EPn16ciVsPQ/ypsjk=" crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/instantsearch.production.min.js" integrity="sha256-LAGhRRdtVoD6RLo2qDQsU2mp+XVSciKRC8XPOBWmofM=" crossorigin="anonymous"></script>

That requires changing my custom JavaScript a bit to match the new library’s coding standards, as well as breaking out my DIVs that need DOM injection into separate search-searchbar and search-poweredby IDs.

    ...
    <p>Hello, world</p>
    <div id="search-searchbar"></div>
    <div id="search-poweredby"></div>
    <p>Well, that was neat</p>
    <!-- Start end-of-page scripts -->
    ...
    <!-- Make InstantSearch put widgets in the DOM -->
    <script>
      // --- Prep InstantSearch ---
      const searchClient = algoliasearch(
        "MY_APP_ID",
        "MY_SEARCH_ONLY_API_KEY"
      );
      const search = instantsearch({
        indexName: "MY_INDEX_NAME",
        searchClient,
      });
      // --- Define some custom helpers ---
      // TO DO
      // --- Add all widgets ---
      search.addWidgets([
        // --- Define the "searchbar" as using the "searchBox" widget
        instantsearch.widgets.searchBox({
          container: "#search-searchbar",
          placeholder: "Search this site...",
          poweredBy: true, // This is required if you're on the free Community plan
          autofocus: false,
        }),
      ]);
      // --- Throw InstantSearch into the DOM ---
      search.start();
    </script>
    <!-- End end-of-page scripts -->
    ...

Here’s the DOM that gets injected from version 4 of InstantSearch (I’d been on version 2):

  <div id="search-searchbar" class="w-16 h-24">
    <div class="ais-SearchBox">
      <form action="" role="search" class="ais-SearchBox-form" novalidate="">
        <input
          class="ais-SearchBox-input"
          type="search"
          placeholder="Search this site..."
          autocomplete="off"
          autocorrect="off"
          autocapitalize="none"
          spellcheck="false"
          maxlength="512"
        /><button
          class="ais-SearchBox-submit"
          type="submit"
          title="Submit the search query."
        >
          <svg
            class="ais-SearchBox-submitIcon"
            xmlns="http://www.w3.org/2000/svg"
            width="10"
            height="10"
            viewBox="0 0 40 40"
          >
            <path
              d="M26.804 29.01c-2.832 2.34-6.465 3.746-10.426 3.746C7.333 32.756 0 25.424 0 16.378 0 7.333 7.333 0 16.378 0c9.046 0 16.378 7.333 16.378 16.378 0 3.96-1.406 7.594-3.746 10.426l10.534 10.534c.607.607.61 1.59-.004 2.202-.61.61-1.597.61-2.202.004L26.804 29.01zm-10.426.627c7.323 0 13.26-5.936 13.26-13.26 0-7.32-5.937-13.257-13.26-13.257C9.056 3.12 3.12 9.056 3.12 16.378c0 7.323 5.936 13.26 13.258 13.26z"
            ></path>
          </svg></button
        ><button
          class="ais-SearchBox-reset"
          type="reset"
          title="Clear the search query."
          hidden=""
        >
          <svg
            class="ais-SearchBox-resetIcon"
            xmlns="http://www.w3.org/2000/svg"
            viewBox="0 0 20 20"
            width="10"
            height="10"
          >
            <path
              d="M8.114 10L.944 2.83 0 1.885 1.886 0l.943.943L10 8.113l7.17-7.17.944-.943L20 1.886l-.943.943-7.17 7.17 7.17 7.17.943.944L18.114 20l-.943-.943-7.17-7.17-7.17 7.17-.944.943L0 18.114l.943-.943L8.113 10z"
            ></path>
          </svg></button
        ><span class="ais-SearchBox-loadingIndicator" hidden=""
          ><svg
            class="ais-SearchBox-loadingIcon"
            width="16"
            height="16"
            viewBox="0 0 38 38"
            xmlns="http://www.w3.org/2000/svg"
            stroke="#444"
          >
            <g fill="none" fillrule="evenodd">
              <g transform="translate(1 1)" strokewidth="2">
                <circle strokeopacity=".5" cx="18" cy="18" r="18"></circle>
                <path d="M36 18c0-9.94-8.06-18-18-18">
                  <animateTransform
                    attributeName="transform"
                    type="rotate"
                    from="0 18 18"
                    to="360 18 18"
                    dur="1s"
                    repeatCount="indefinite"
                  ></animateTransform>
                </path>
              </g>
            </g></svg
        ></span>
      </form>
    </div>
  </div>
  <div id="search-poweredby" class="w-6 h-2">
    <div class="ais-PoweredBy ais-PoweredBy--light">
      <a
        href="https://www.algolia.com/?utm_source=instantsearch.js&amp;utm_medium=website&amp;utm_content=&amp;utm_campaign=poweredby"
        target="_blank"
        class="ais-PoweredBy-link"
        aria-label="Search by Algolia"
        rel="noopener noreferrer"
        ><svg
          height="1.2em"
          class="ais-PoweredBy-logo"
          viewBox="0 0 168 24"
          style="width: auto"
        >
          <path
            fill="#5D6494"
            d="M6.97 6.68V8.3a4.47 4.47 0 0 0-2.42-.67 2.2 2.2 0 0 0-1.38.4c-.34.26-.5.6-.5 1.02 0 .43.16.77.49 1.03.33.25.83.53 1.51.83a7.04 7.04 0 0 1 1.9 1.08c.34.24.58.54.73.89.15.34.23.74.23 1.18 0 .95-.33 1.7-1 2.24a4 4 0 0 1-2.6.81 5.71 5.71 0 0 1-2.94-.68v-1.71c.84.63 1.81.94 2.92.94.58 0 1.05-.14 1.39-.4.34-.28.5-.65.5-1.13 0-.29-.1-.55-.3-.8a2.2 2.2 0 0 0-.65-.53 23.03 23.03 0 0 0-1.64-.78 13.67 13.67 0 0 1-1.11-.64c-.12-.1-.28-.22-.46-.4a1.72 1.72 0 0 1-.39-.5 4.46 4.46 0 0 1-.22-.6c-.07-.23-.1-.48-.1-.75 0-.91.33-1.63 1-2.17a4 4 0 0 1 2.57-.8c.97 0 1.8.18 2.47.52zm7.47 5.7v-.3a2.26 2.26 0 0 0-.5-1.44c-.3-.35-.74-.53-1.32-.53-.53 0-.99.2-1.37.58-.38.39-.62.95-.72 1.68h3.91zm1 2.79v1.4c-.6.34-1.38.51-2.36.51a4.02 4.02 0 0 1-3-1.13 4.04 4.04 0 0 1-1.11-2.97c0-1.3.34-2.32 1.02-3.06a3.38 3.38 0 0 1 2.6-1.1c1.03 0 1.85.32 2.46.96.6.64.9 1.57.9 2.78 0 .33-.03.68-.09 1.04h-5.31c.1.7.4 1.24.89 1.61.49.38 1.1.56 1.85.56.86 0 1.58-.2 2.15-.6zm6.61-1.78h-1.21c-.6 0-1.05.12-1.35.36-.3.23-.46.53-.46.89 0 .37.12.66.36.88.23.2.57.32 1.02.32.5 0 .9-.15 1.2-.43.3-.28.44-.65.44-1.1v-.92zm-4.07-2.55V9.33a4.96 4.96 0 0 1 2.5-.55c2.1 0 3.17 1.03 3.17 3.08V17H22.1v-.96c-.42.68-1.15 1.02-2.19 1.02-.76 0-1.38-.22-1.84-.66-.46-.44-.7-1-.7-1.68 0-.78.3-1.38.88-1.81.59-.43 1.4-.65 2.46-.65h1.34v-.46c0-.55-.13-.97-.4-1.25-.26-.29-.7-.43-1.32-.43-.86 0-1.65.24-2.35.72zm9.34-1.93v1.42c.39-1 1.1-1.5 2.12-1.5.15 0 .31.02.5.05v1.53c-.23-.1-.48-.14-.76-.14-.54 0-.99.24-1.34.71a2.8 2.8 0 0 0-.52 1.71V17h-1.57V8.91h1.57zm5 4.09a3 3 0 0 0 .76 2.01c.47.53 1.14.8 2 .8.64 0 1.24-.18 1.8-.53v1.4c-.53.32-1.2.48-2 .48a3.98 3.98 0 0 1-4.17-4.18c0-1.16.38-2.15 1.14-2.98a4 4 0 0 1 3.1-1.23c.7 0 1.34.15 1.92.44v1.44a3.24 3.24 0 0 0-1.77-.5A2.65 2.65 0 0 0 32.33 13zm7.92-7.28v4.58c.46-1 1.3-1.5 2.5-1.5.8 0 1.42.24 1.9.73.48.5.72 1.17.72 2.05V17H43.8v-5.1c0-.56-.14-.99-.43-1.29-.28-.3-.65-.45-1.1-.45-.54 0-1 .2-1.42.6-.4.4-.61 1.02-.61 1.85V17h-1.56V5.72h1.56zM55.2 15.74c.6 0 1.1-.25 1.5-.76.4-.5.6-1.16.6-1.95 0-.92-.2-1.62-.6-2.12-.4-.5-.92-.74-1.55-.74-.56 0-1.05.22-1.5.67-.44.45-.66 1.13-.66 2.06 0 .96.22 1.67.64 2.14.43.47.95.7 1.57.7zM53 5.72v4.42a2.74 2.74 0 0 1 2.43-1.34c1.03 0 1.86.38 2.51 1.15.65.76.97 1.78.97 3.05 0 1.13-.3 2.1-.92 2.9-.62.81-1.47 1.21-2.54 1.21s-1.9-.45-2.46-1.34V17h-1.58V5.72H53zm9.9 11.1l-3.22-7.9h1.74l1 2.62 1.26 3.42c.1-.32.48-1.46 1.15-3.42l.91-2.63h1.66l-2.92 7.87c-.78 2.07-1.96 3.1-3.56 3.1-.28 0-.53-.02-.73-.07v-1.34c.17.04.35.06.54.06 1.03 0 1.76-.57 2.17-1.7z"
          ></path>
          <path
            fill="#5468FF"
            d="M78.99.94h16.6a2.97 2.97 0 0 1 2.96 2.96v16.6a2.97 2.97 0 0 1-2.97 2.96h-16.6a2.97 2.97 0 0 1-2.96-2.96V3.9A2.96 2.96 0 0 1 79 .94"
          ></path>
          <path
            fill="#FFF"
            d="M89.63 5.97v-.78a.98.98 0 0 0-.98-.97h-2.28a.98.98 0 0 0-.97.97V6c0 .09.08.15.17.13a7.13 7.13 0 0 1 3.9-.02c.08.02.16-.04.16-.13m-6.25 1L83 6.6a.98.98 0 0 0-1.38 0l-.46.46a.97.97 0 0 0 0 1.38l.38.39c.06.06.15.04.2-.02a7.49 7.49 0 0 1 1.63-1.62c.07-.04.08-.14.02-.2m4.16 2.45v3.34c0 .1.1.17.2.12l2.97-1.54c.06-.03.08-.12.05-.18a3.7 3.7 0 0 0-3.08-1.87c-.07 0-.14.06-.14.13m0 8.05a4.49 4.49 0 1 1 0-8.98 4.49 4.49 0 0 1 0 8.98m0-10.85a6.37 6.37 0 1 0 0 12.74 6.37 6.37 0 0 0 0-12.74"
          ></path>
          <path
            fill="#5468FF"
            d="M120.92 18.8c-4.38.02-4.38-3.54-4.38-4.1V1.36l2.67-.42v13.25c0 .32 0 2.36 1.71 2.37v2.24zm-10.84-2.18c.82 0 1.43-.04 1.85-.12v-2.72a5.48 5.48 0 0 0-1.57-.2c-.3 0-.6.02-.9.07-.3.04-.57.12-.81.24-.24.11-.44.28-.58.49a.93.93 0 0 0-.22.65c0 .63.22 1 .61 1.23.4.24.94.36 1.62.36zm-.23-9.7c.88 0 1.62.11 2.23.33.6.22 1.09.53 1.44.92.36.4.61.92.76 1.48.16.56.23 1.17.23 1.85v6.87c-.4.1-1.03.2-1.86.32-.84.12-1.78.18-2.82.18-.69 0-1.32-.07-1.9-.2a4 4 0 0 1-1.46-.63c-.4-.3-.72-.67-.96-1.13a4.3 4.3 0 0 1-.34-1.8c0-.66.13-1.08.39-1.53.26-.45.6-.82 1.04-1.1.45-.3.95-.5 1.54-.62a8.8 8.8 0 0 1 3.79.05v-.44c0-.3-.04-.6-.11-.87a1.78 1.78 0 0 0-1.1-1.22c-.31-.12-.7-.2-1.15-.2a9.75 9.75 0 0 0-2.95.46l-.33-2.19c.34-.12.84-.23 1.48-.35.65-.12 1.34-.18 2.08-.18zm52.84 9.63c.82 0 1.43-.05 1.85-.13V13.7a5.42 5.42 0 0 0-1.57-.2c-.3 0-.6.02-.9.07-.3.04-.57.12-.81.24-.24.12-.44.28-.58.5a.93.93 0 0 0-.22.65c0 .63.22.99.61 1.23.4.24.94.36 1.62.36zm-.23-9.7c.88 0 1.63.11 2.23.33.6.22 1.1.53 1.45.92.35.39.6.92.76 1.48.15.56.23 1.18.23 1.85v6.88c-.41.08-1.03.19-1.87.31-.83.12-1.77.18-2.81.18-.7 0-1.33-.06-1.9-.2a4 4 0 0 1-1.47-.63c-.4-.3-.72-.67-.95-1.13a4.3 4.3 0 0 1-.34-1.8c0-.66.13-1.08.38-1.53.26-.45.61-.82 1.05-1.1.44-.3.95-.5 1.53-.62a8.8 8.8 0 0 1 3.8.05v-.43c0-.31-.04-.6-.12-.88-.07-.28-.2-.52-.38-.73a1.78 1.78 0 0 0-.73-.5c-.3-.1-.68-.2-1.14-.2a9.85 9.85 0 0 0-2.95.47l-.32-2.19a11.63 11.63 0 0 1 3.55-.53zm-8.03-1.27a1.62 1.62 0 0 0 0-3.24 1.62 1.62 0 1 0 0 3.24zm1.35 13.22h-2.7V7.27l2.7-.42V18.8zm-4.72 0c-4.38.02-4.38-3.54-4.38-4.1l-.01-13.34 2.67-.42v13.25c0 .32 0 2.36 1.72 2.37v2.24zm-8.7-5.9a4.7 4.7 0 0 0-.74-2.79 2.4 2.4 0 0 0-2.07-1 2.4 2.4 0 0 0-2.06 1 4.7 4.7 0 0 0-.74 2.8c0 1.16.25 1.94.74 2.62a2.4 2.4 0 0 0 2.07 1.02c.88 0 1.57-.34 2.07-1.02.49-.68.73-1.46.73-2.63zm2.74 0a6.46 6.46 0 0 1-1.52 4.23c-.49.53-1.07.94-1.76 1.22-.68.29-1.73.45-2.26.45-.53 0-1.58-.15-2.25-.45a5.1 5.1 0 0 1-2.88-3.13 7.3 7.3 0 0 1-.01-4.84 5.13 5.13 0 0 1 2.9-3.1 5.67 5.67 0 0 1 2.22-.42c.81 0 1.56.14 2.24.42.69.29 1.28.69 1.75 1.22.49.52.87 1.15 1.14 1.89a7 7 0 0 1 .43 2.5zm-20.14 0c0 1.11.25 2.36.74 2.88.5.52 1.13.78 1.91.78a4.07 4.07 0 0 0 2.12-.6V9.33c-.19-.04-.99-.2-1.76-.23a2.67 2.67 0 0 0-2.23 1 4.73 4.73 0 0 0-.78 2.8zm7.44 5.27c0 1.82-.46 3.16-1.4 4-.94.85-2.37 1.27-4.3 1.27-.7 0-2.17-.13-3.34-.4l.43-2.11c.98.2 2.27.26 2.95.26 1.08 0 1.84-.22 2.3-.66.46-.43.68-1.08.68-1.94v-.44a5.2 5.2 0 0 1-2.54.6 5.6 5.6 0 0 1-2.01-.36 4.2 4.2 0 0 1-2.58-2.71 9.88 9.88 0 0 1 .02-5.35 4.92 4.92 0 0 1 2.93-2.96 6.6 6.6 0 0 1 2.43-.46 19.64 19.64 0 0 1 4.43.66v10.6z"
          ></path></svg
      ></a>
    </div>
  </div>

As before:

  • Unstyled code looks ugly (although not nearly as ugly as w/ v2).
  • Algolia-delivered stylesheets for “searchbox” & “poweredby” widgets try to overflow height restrictions.
  • “searchbox” Algolia-delivered stylesheets fit width into width restrictions.
  • “poweredby” Algolia-delivered stylesheets try to overflow width restrcitions.
  • Since “search by” is no longer incorporated into the searchbox, it no longer tries to right-align itself to anything.

URL query parameter handling

I want to be able to include a search box with very little client-side JavaScript in every page of my site, and then let the Submit action take people to /search?q=THEIR_SEARCH_WORDS.

There’s a shortcut for this: I Just had to add routing: true to my instantsearch() initalization code:

      const search = instantsearch({
        indexName: "MY_INDEX_NAME",
        searchClient,
        routing: true,
      });

I navigated my browser to file:///C:/example/algoliaindex.html?MY_INDEX_NAME%5Bquery%5D=world and observed my request come in at https://algolia.com/apps/MY_APP_ID/monitoring/logs with a Request body whose params included the phrase query=world. Furthermore, world shows up prepopulated in the search box rather than the placeholder text. Neat.

For the longest time, I thought that Algolia’s docs were trying to tell me that after the ? it would need to be instant_search[query]=world, and that wasn’t doing anything for me even after I added routing: true, but it turns out that their particular sample index name was instant_search – that wasn’t a magic keyword for the Instant Search library.

What I needed to do, to get URL parameters working with routing: true on, was put my own index name into the URL.

I find it awkward to use the name of my Algolia index in URL parameters (I chose a weird name), so I want to keep working through the instructions about customizing URL parameter handling.

I tried this per the Routing URLs docs, but not only did ?instant_search[query]=world stop working, ?q=world didn’t work yet, either.

      ...
      // --- Prep InstantSearch ---
      const searchClient = algoliasearch(
        "MY_APP_ID",
        "MY_SEARCH_ONLY_API_KEY"
      );
      const indexName = 'MY_INDEX_NAME';
      const search = instantsearch({
        indexName,
        searchClient,
        routing: {
          stateMapping: {
            stateToRoute(uiState) {
                const indexUiState = uiState[indexName];
                return {
                  q: indexUiState.query,
                }
            },
            routeToState(routeState) {
              return {
                [indexName]: {
                  q: routeState.q,
                }
              }
            },
          },
        },
      });
      // --- Define some custom helpers ---
      // TO DO
      ...

I searched the internet for statetoroute routetostate and found a CodeSandbox called “InstantSearch.js - URLSync without page - CodeSandbox” that got things working, although the query parameter is query, not q, and the world query doesn’t show up at all in the codebase, so that’s interesting.

Here’s what my custom scripting looks like now:

    ...
      // --- Prep InstantSearch ---
      const searchClient = algoliasearch(
        "MY_APP_ID",
        "MY_SEARCH_ONLY_API_KEY"
      );
      const indexName = "MY_INDEX_NAME";
      const singleIndexStateMapping = instantsearch.stateMappings.singleIndex(indexName);
      const withoutPageStateMapping = {
        stateToRoute(uiState) {
          const { page, ...state } = singleIndexStateMapping.stateToRoute(uiState);
          return state;
        },
        routeToState(routeState) {
          const { [indexName]: indexUiState } = singleIndexStateMapping.routeToState(routeState);
          const { page, ...state } = indexUiState;
          return { [indexName]: state, };
        },
      };
      const search = instantsearch({
        indexName,
        searchClient,
        routing: { stateMapping: withoutPageStateMapping },
      });
      // --- Define some custom helpers ---
      // TO DO
      // --- Add all widgets ---
      search.addWidgets([
        // --- Define the "searchbar" as using the "searchBox" widget
        instantsearch.widgets.searchBox({
          container: "#search-searchbar",
          placeholder: "Search this site...",
          poweredBy: true, // This is required if you're on the free Community plan
          autofocus: false,
        }),
        instantsearch.widgets.poweredBy({
          container: "#search-poweredby",
        }),
      ]);
      // --- Throw InstantSearch into the DOM ---
      search.start();
    ...

I don’t read JavaScript well enough to have the slightest clue why it works, but I’m happy it does.

Adding a search bar to every page

Additional resources

  • https://blog.floriancourgey.com/2018/11/migrate-from-wordpress-to-jekyll-2
--- ---