Add Custom Location Result Cards | Yext Hitchhikers Platform
What You’ll Learn
In this section, you will:
- Generate Typescript types for search results with the Yext CLI
- Create a custom
LocationResultcomponent and use it withVerticalResultsto display more information for each result
Overview
In this unit, you will create custom Location result cards. You will then pass the custom card to VerticalResults to display each result with more information about each location.
In the next two units, you are going to use React Icons for some custom styling. Add them to your project with the following command:
npm i react-icons1. Generate Types For Your Search Experience
The Yext CLI comes with a handy tool for generating Typescript types for a particular search experience. You can read more about typing with Yext Search here .
In the terminal, run the following command:
yext types generate search src/types --experienceKey turtlehead-tacos-locatorCheck out the new locations.ts file that was generated for you inside of src/types. You’ll notice that the Location type contains all the possible fields that could be included in a Location search result.
2. Create a Custom Location Result Card
Right now, you are using the StandardCard with VerticalResults in the StoreLocator component to display location results, which only displays the name and description fields for each result. To display more information, let’s create a custom LocationCard to display the address and neighborhood fields as well!
In src/components, add a new file called LocationCard.tsx and add the following code:
// src/components/LocationCard.tsx
import { CardComponent, CardProps } from "@yext/search-ui-react";
import Location, { Coordinate } from "../types/locations";
import { RiDirectionFill } from "react-icons/ri";
const LocationCard: CardComponent<Location> = ({
result,
}: CardProps<Location>): JSX.Element => {
const location = result.rawData;
// function that takes coordinates and returns a google maps link for directions
const getGoogleMapsLink = (coordinate: Coordinate): string => {
return `https://www.google.com/maps/dir/?api=1&destination=${coordinate.latitude},${coordinate.longitude}`;
};
return (
<div className="flex justify-between border-y p-4">
<div className="flex">
<div>
<a
target={"_blank"}
href={location.slug}
className="font-semibold text-orange"
rel="noreferrer"
>
{location.neighborhood}
</a>
<p className="text-sm">{location.address.line1}</p>
<p className="text-sm">{`${location.address.city}, ${location.address.region} ${location.address.postalCode}`}</p>
</div>
</div>
<div className="flex items-center">
{location.yextDisplayCoordinate && (
<a
target={"_blank"}
className="flex flex-col items-center text-sm text-orange"
href={getGoogleMapsLink(location.yextDisplayCoordinate)}
rel="noreferrer"
>
<RiDirectionFill size={24} />
<p>Directions</p>
</a>
)}
</div>
</div>
);
};
export default LocationCard;Let’s review what you just added:
CardComponentis generically typed. By passingLocationas the type parameter toCardProps, therawDataon theresultprop will be typed as aLocation. You can learn more about Typescript generics here .- You are displaying the
neighborhoodrather than thenameof the location and wrapping it in anatag that links out to the landing page for the location. - You are taking the
address, formatting it, and displaying it below theneighborhood. - You have wrapped an icon with an
atag that will link out to Google Maps with directions to that particular location.
3. Add the LocationCard to VerticalResults
Now that you new result cards are ready to go, pass LocationCard as the CardComponent prop to VerticalResults in your StoreLocator component:
// src/components/StoreLocator.tsx
import {
MapboxMap,
FilterSearch,
OnSelectParams,
VerticalResults,
} from "@yext/search-ui-react";
import {
Matcher,
SelectableStaticFilter,
useSearchActions,
} from "@yext/search-headless-react";
// Mapbox CSS bundle
import "mapbox-gl/dist/mapbox-gl.css";
import LocationCard from "./LocationCard"; // New
const StoreLocator = (): JSX.Element => {
const searchActions = useSearchActions();
const handleFilterSelect = (params: OnSelectParams) => {
const locationFilter: SelectableStaticFilter = {
displayName: params.newDisplayName,
selected: true,
filter: {
kind: "fieldValue",
fieldId: params.newFilter.fieldId,
value: params.newFilter.value,
matcher: Matcher.Equals,
},
};
searchActions.setStaticFilters([locationFilter]);
searchActions.executeVerticalQuery();
};
return (
<>
<div className="flex h-[calc(100vh-242px)] border">
<div className="w-1/3 flex flex-col">
<FilterSearch
onSelect={handleFilterSelect}
placeholder="Find Locations Near You"
searchFields={[
{
entityType: "location",
fieldApiName: "builtin.location",
},
]}
/>
<VerticalResults
customCssClasses={{ verticalResultsContainer: "overflow-y-auto" }}
CardComponent={LocationCard} // New
/>
</div>
<div className="w-2/3">
<MapboxMap
mapboxAccessToken={YEXT_PUBLIC_MAPBOX_API_KEY || ""}
/>
</div>
</div>
</>
);
};
export default StoreLocator;If your site isn’t already running, start it back up with npm run dev and go the locator page. Search for “New York City, New York, NY” to see your new result cards.