FilterSearch| Hitchhikers Platform

Storybook

Filter Search allows the user to search for a filter to apply to their search - such as a location, a category, or a medical specialty. This is a common UX pattern, as it presents the user with all possible options and forces them to select a valid one.

You’ll find a similar UI on sites like Google Flights and Zocdoc. Notice how on these sites you must select certain filters - like the arrival and destination city - before you conduct your search.

Here’s what what <FilterSearch/> looks like:

Under the hood, this component uses the filter search API endpoint. Like the autocomplete endpoint, this endpoint is designed to be hit with each keystroke, and it returns a series of filters instead of search results. Filter search can only be used on vertical search, so it’s ideal for things like a store locator, doctor finder, or product search.


Basic Example

To make a field eligible for filter search, make sure that it’s set as "staticFilter": true in the search configuration. This exposes the field in the filter search API and allows static filters to be applied on that field. For example:

{
  "$schema": "https://schema.yext.com/config/answers/answers-config/v1",
  "verticals": {
    "doctors": {
      "entityTypes": ["doctor"],
      "searchableFields": {
        "speciality": {
          "staticFilter": true

      }
    }
  }
}

Once that’s done, you can use the <FilterSearch/> component like so:

import {
  SearchBar,
  StandardCard,
  VerticalResults,
  FilterSearch,
} from "@yext/search-ui-react";
import { useSearchActions } from "@yext/search-headless-react";
import { useEffect } from "react";

const App = (): JSX.Element => {
  const searchActions = useSearchActions();

  useEffect(() => {
    searchActions.setVertical("doctors");
  }, []);

  return (
    <div className="flex justify-center px-4 py-6">
      <div className="w-full max-w-5xl">
        <SearchBar />
        <div className="flex">
          <FilterSearch
            customCssClasses={{ filterSearchContainer: "mr-10" }}
            searchFields={[
              {
                entityType: "doctor",
                fieldApiName: "speciality",
              },
            ]}
          />
          <VerticalResults
            customCssClasses={{ verticalResultsContainer: "flex-grow" }}
            CardComponent={StandardCard}
          />
        </div>
      </div>
    </div>
  );
};

export default App;

As the user starts typing in the filter search bar, they will see autocomplete suggestions for filters that match both of these fields. For example, if they type in car, they’ll see Cardiology as a specialty filter. If the user selects one of these filters, it will be applied as static filter in state.

To run the search, you can use the searchOnSelect property:

<FilterSearch
  customCssClasses={{ filterSearchContainer: "mr-10" }}
  searchFields={[
    {
      entityType: "doctor",
      fieldApiName: "speciality",
    },
  ]}
/>

Or you could import the <ApplyFiltersButton /> and place it under your filter search where the user can execute the search:

import {
  SearchBar,
  StandardCard,
  VerticalResults,
  FilterSearch,
  ApplyFiltersButton,
} from "@yext/search-ui-react";
import { useSearchActions } from "@yext/search-headless-react";
import { useEffect } from "react";

const App = (): JSX.Element => {
  const searchActions = useSearchActions();

  useEffect(() => {
    searchActions.setVertical("doctors");
  }, []);

  return (
    <div className="flex justify-center px-4 py-6">
      <div className="w-full max-w-5xl">
        <SearchBar />
        <div className="flex">
          <div>
            <FilterSearch
              customCssClasses={{ filterSearchContainer: "mr-10" }}
              searchFields={[
                {
                  entityType: "doctor",
                  fieldApiName: "speciality",
                },
              ]}
            />
            <ApplyFiltersButton />
          </div>
          <VerticalResults
            customCssClasses={{ verticalResultsContainer: "flex-grow" }}
            CardComponent={StandardCard}
          />
        </div>
      </div>
    </div>
  );
};

export default App;


Sectioning

In the first example, filter search only looked for filters on one field (specialty). But it’s also common to use a single filter search bar to search multiple different fields. For this, you can add additional fields to the searchFields array and add the sectioned flag to separate the results.

For example, a single search bar could search both specialty in location:

<FilterSearch
  sectioned
  searchFields={[
    {
      entityType: "doctor",
      fieldApiName: "specialty",
    },
    {
      entityType: "location",
      fieldApiName: "builtin.location",
    },
  ]}
/>

Now when the user types in car, they’ll not only see Cardiology but also Carlisle, Pennsylvania as filter options.


Combining Filter Search Bars

It’s common to use multiple filter search bars together, or to use them in conjunction with a standard <SearchBar/>. Returning to the example above - you might want users to first have to select a specialty, then select a location separately. You could accomplish this by stacking two filter search bars next to each other, like so:

import {
  FilterSearch,
  ApplyFiltersButton,
  VerticalResults,
  StandardCard,
} from "@yext/search-ui-react";
import { useSearchActions } from "@yext/search-headless-react";
import { useEffect } from "react";

const App = (): JSX.Element => {
  const searchActions = useSearchActions();
  useEffect(() => {
    searchActions.setVertical("doctors");
  }, []);

  return (
    <div className="flex justify-center px-4 py-6">
      <div className="w-full max-w-5xl">
        <div className="flex space-x-4">
          <FilterSearch
            searchFields={[
              {
                entityType: "doctor",
                fieldApiName: "specialty",
              },
            ]}
          />
          <FilterSearch
            searchFields={[
              {
                entityType: "doctor",
                fieldApiName: "builtin.location",
              },
            ]}
          />
        </div>
        <ApplyFiltersButton />
        <VerticalResults CardComponent={StandardCard} />
      </div>
    </div>
  );
};

export default App;

Another common pattern is to combine a filter search bar with a standard search bar. For example, you might want to require a user to select a location, but then let them type in whatever they want for in a free-form search bar. You can do this too:

import {
  FilterSearch,
  ApplyFiltersButton,
  VerticalResults,
  StandardCard,
} from "@yext/search-ui-react";
import { useSearchActions } from "@yext/search-headless-react";
import { useEffect } from "react";

const App = (): JSX.Element => {
  const searchActions = useSearchActions();
  useEffect(() => {
    searchActions.setVertical("doctors");
  }, []);

  return (
    <div className="flex justify-center px-4 py-6">
      <div className="w-full max-w-5xl">
        <div className="flex space-x-4">
          <FilterSearch
            searchFields={[
              {
                entityType: "doctor",
                fieldApiName: "specialty",
              },
            ]}
          />
          <SearchBar />
        <ApplyFiltersButton />
        <VerticalResults CardComponent={StandardCard} />
      </div>
    </div>
  );
};

export default App;
Feedback