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
LocationResult
component and use it withVerticalResults
to 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-icons
1. 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-locator
Check 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:
CardComponent
is generically typed. By passingLocation
as the type parameter toCardProps
, therawData
on theresult
prop will be typed as aLocation
. You can learn more about Typescript generics here .- You are displaying the
neighborhood
rather than thename
of the location and wrapping it in ana
tag 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
a
tag 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.