This resource contains various code examples that were created to customize and style the Search frontend. You can copy and paste the code into your own experiences or modify them to fit your design needs.
Note: these snippets were created with the Frontend Theme in mind but can be adapted if you are creating sites in JS or React.
Navigation Bar
Updating Font Color
To change the color of the nav bar text, you can add the following to the answers-variables.scss file:
--yxt-nav-text-color: red;
You could also use the following CSS, but you will need to target each part of the navigation bar as well as the hover state if you want similar colors and behaviors as above. .yxt-Nav-item allows you to change the color of the default nav bar labels and .yxt-Nav-item.is-active lets you change the color of the navigation bar label and its bottom border once a vertical is clicked.
.yxt-Nav-item {
color: orange;
&:hover {
color: red;
}
}
.yxt-Nav-item.is-active {
color: red;
border-bottom-color: red;
}

Background
Adding an Image as Search Background
You can use the background-image property to set a background image, using code such as the below. If you are using the Code Editor, make sure to place this outside of the .Answers{} class in the answers.scss file.
body, .Answers-footer, .Answers-navWrapper {
background-image: url("https://hitchhikers.yext.com/img/onward/metaimage.jpg");
background-size: 100%;
}
You can either use the absolute URL of the image if it exists online or upload the image to your assets folder and reference it such as in the Add Images and Fonts unit.
Additionally, you may need to add additional CSS to adjust the size of the image and account for different device types.

Adding Background Image to Promo Banner
You can also add an image as the background of a promo banner. Read more on how to set up a promo vertical, here.
.promo-card {
background-image: url("../assets/images/background.png");
}

Using Linear Gradients as a Background
body, .Answers-footer, .Answers-navWrapper {
background-image:linear-gradient(240deg, red, yellow, green);
}
If you are using the Code Editor, make sure to place this outside of the .Answers{} class in the answers.scss file.

Using Linear Gradients in the Results Title Bar
.HitchhikerResultsStandard-title {
background-image: linear-gradient(to right, red, orange, yellow);
}

Facets and Sorting
Squaring Off Filter Button
Add the following to the answers.scss file:
.yxt-FilterOptions-optionLabel:before {
border-radius: 0;
}
Filter Button Color
Add the following to the answers.scss file:
.yxt-FilterOptions-optionLabel:after {
border-right: 0.0625rem solid var(--yxt-color-brand-primary);
border-bottom: 0.0625rem solid var(--yxt-color-brand-primary);
}
SortOptions and Facets Side-by-Side
To have SortOptions and Facets appear next to each other, add a div that wraps the sorting and facets components in the [[vertical]].html.hbs file. In the example below, the new div is called Answers-searchOptions:
<div class="Answers-resultsWrapper">
<div class="Answers-resultsColumn">
{{> templates/vertical-map/markup/spellcheck }}
<div class="Answers-searchOptions"> {{!-- new div --}}
{{> templates/vertical-map/markup/sortoptions }}
{{> templates/vertical-map/markup/facets }}
</div> {{!-- new div --}}
</div>
</div>
Then format it using display: flex in the answers.scss file:
&-searchOptions {
display: flex;
}
You'll probably want to tweak the padding on the components so they're more aligned, and you can use width or flex-basis to make the components take up different amounts of space if you want.
Results Page
Alert Banner
If you want to show a banner any time results are displayed, add the following to the handlebars file of the vertical of your choosing (e.g. faqs.html.hbs) within the Answers-resultsWrapper div:
<div class="Answers-alertBanner">For urgent requests, please call our <a href="tel:999-999-9999">emergency hotline</a></div>
It should look something like this:
<div class="Answers-container Answers-resultsWrapper">
{{> templates/vertical-standard/markup/spellcheck }}
<div class="Answers-alertBanner">For urgent requests, please call our <a href="tel:999-999-9999">emergency hotline</a></div>
<div class="Answers-filtersAndResults">
{{!-- <div class="Answers-filtersWrapper"> --}}
{{!-- {{> templates/vertical-standard/markup/sortoptions }} --}}
{{!-- {{> templates/vertical-standard/markup/filterbox }} --}}
{{!-- {{> templates/vertical-standard/markup/facets }} --}}
{{!-- </div> --}}
{{> templates/vertical-standard/markup/verticalresults }}
</div>
{{> templates/vertical-standard/markup/pagination }}
{{!-- {{> templates/vertical-standard/markup/qasubmission }} --}}
</div>
We can also add the below CSS for the .Answers-alertBanner class in our answers.scss file.
.Answers-alertBanner {
width: 100%;
text-align: center;
background: var(--yxt-color-brand-primary);
padding: 1rem;
margin-bottom: 1rem;
color: white;
font-weight: bold;
a {
text-decoration: underline;
&:hover {
text-decoration: none;
}
}
}

Changing Chevron Image on Universal View All to an SVG
You'll want to use the file path of the image you saved in the assets/images folder. In this example we will use "static/assets/images/double-echelon.svg".
![]()
Depending on what theme you are on, the structure of your files may be different. With theme 1.28, the view more partial in the universalsectiontemplates looks like this:
![]()
Rather than calling the icon name directly here, the template calls an icon partial instead. This is to help consolidate and make sure all places that use this icon are now referencing the same icon. Once you override this theme file, you can replace the icon div with this div:
<div data-component="IconComponent"
data-opts='{"iconUrl": "static/assets/images/double-echelon.svg"}'
data-prop="icon">
It should look something like this in the Code Editor:
![]()
Note that you will need to override all universalsectiontemplates you're using, such as standard and grid-three-columns.
Infinite Scroll with Search UI React
You may want to fetch search results when scrolling to the bottom of a page, rather than using a pagination component. This method is commonly referred to as infinite scroll. I put together this Code Sandbox that demonstrates how to accomplish infinite scroll with Search UI React.
I want to highlight a few key points about this implementation:
- Rather than use the
VerticalResultscomponent that is tightly coupled with the Search Headless vertical results, I am mapping over results stored in the component state. - When you set a function as an event listener using
addEventListener, the function will use the state and props that were present at the time it was created. Therefore, to ensure that the event listener function has access to the latest state and props, I am using a technique called "closing over" the state and props using theuseCallbackhook. -
searchLoadingneeds to be added to theuseCallbackdependency array to ensure that the same page of results are not fetched twice.
Result Card Structure
The following code snippets cover examples of changing the card structure, whether you're adding more content or shifting components around.
For code snippets on styling result cards, see the Result Card Styling section below.
Add New Fields
Add Email to Cards
In order to do this the right way, we'll need to do three things:
1. Update the custom card's component.js to pass through the Email field, as well as the details needed to successfully fire an Analytics event.
email: profile.emails ? profile.emails[0] : null, emailEventOptions: this.addDefaultEventOptions(),
The email attribute passes in the first email address of the Emails field (if populated), otherwise returns null. Modify this to align with the field that stores your email addresses.
The emailEventOptions attribute just passes the standard data (entity ID, universal vs. vertical search, etc.) that allows us to fire an Analytics event.
2. Update the custom card's template.hbs to add a section for Email that correctly formats the link.
First, we'll create an {{> email}} partial. Add the below within the template.hbs file, preferably below the {{#*inline 'phone'}} partial.
{{#*inline 'email'}} {{#if card.email}}
<div class="HitchhikerLocationStandard-email">
<a
href="mailto:{{card.email}}"
data-eventtype="EMAIL"
data-eventoptions="{{json card.emailEventOptions}}"
target="_blank"
>
{{card.email}}
</a>
</div>
{{/if}} {{/inline}}
Here, we've added a new class HitchhikerLocationStandard-email that allows us to style this email in the future. We're then adding a link — to create an email link, simply add mailto: in front of the email address. We're also passing data-eventtype and data-eventoptions so that an EMAIL event fires when a user clicks on the link. Lastly, the text of the link will be the email itself, enclosed within the <a> tag.
Now that we've defined the partial, we need to reference it so it's placed on the card. If you're forking from a location-standard or professional-standard card, you can navigate to the contactInfo partial in your file and add the email partial underneath the address & phone.
{{#* inline "contactInfo"}}
<div class="HitchhikerLocationStandard-contactInfo">
{{#if (any card.phone card.address card.email)}}
<div class="HitchhikerLocationStandard-core">
{{> address }}
{{> phone }}
{{> email }}
</div>
{{/if}}
You'll see that we both added the card.email in the #if statement, as well as added the partial below the address and phone partials.
3. Optional — add CSS to update the link styling
Add the following to the answers.scss file:
.HitchhikerLocationStandard-email {
color: var(--yxt-color-brand-primary);
margin-top: 0.5rem;
a {
text-decoration: underline;
&:hover {
text-decoration: none;
}
}
}
Change Text Based on Boolean
You may want to use a boolean field to determine what text to display.
In this example, we have a "Work Remote" boolean field and want the subtitle of the card to display Yes/No depending on what the value is. You can do this using a JavaScript ternary operator:
subtitle: 'Work Remote: ' + (profile.workRemote ? 'Yes' : 'No')
This is saying if profile.workRemote is true, then return 'Yes', else return 'No'. You can also return a dynamic value by replacing 'Yes' and 'No' with the field to pull from.
Restructure Card
Use Conditional Placeholder Images
One common issue we've seen is gaps in data, especially for images such as for headshots.

This example walks through using the JavaScript conditional operator to use placeholder images for any agents missing a headshot image, where the placeholder images differ by gender. In other words, the logic is as follows:
- If the
Headshotfield is populated, use that image. - If the
Headshotfield is empty and theGenderfield is set to Female, use the female placeholder image. - Otherwise, fall back to the generic placeholder image.
Learn more about null checks.
Add the following image property in the component.js file of the desired forked card:
return {
title: profile.name, // The header text of the card
subtitle: profile.c_area, // The sub-header text of the card
image: profile.headshot ? Formatter.image(profile.headshot).url : (profile.gender === 'Female' ? 'https://a.mktgcdn.com/p-sandbox/y0iJHYFeCERihQg0qv7j88TBeEnpHq-v_BLyHiDXOb8/142x200.png' : 'https://a.mktgcdn.com/p-sandbox/6DD2AHZA1kbe8M9ZQGW_JOwXFyWNnRTMDJXIGxvQK-4/321x450.jpg'),
...
}

Display Multiple Components on the Same Line
To display multiple components on the same line, you'll have to slightly modify the card template and add some CSS. In this example, we're putting the title and subtitle next to each other.
- Add a
divaround thetitleandsubtitlein the top portion of thetemplate.hbsfile you want to edit. It should look something like this:
<div class="HitchhikerMenuItemStandard-body">
<div class="HitchhikerTitleWrapper">
{{> title }}
{{> subtitle }}
</div>
This will group the two together and allow you to manipulate the layout with CSS styling. Note we named the new div HitchhikerTitleWrapper but you can name it anything as long as you reference it correctly in the next step.
- Add the following snippet to the
answers.scssfile to move thesubtitlenext to thetitle:
.HitchhikerTitleWrapper {
flex-direction: row;
display: flex;
}
You may need to toggle with the padding, margins, and line height after the fact to space them out properly.
Use a Custom Icon on FAQ Accordion Cards
You can change the toggle icon on the FAQ Accordion card from the default chevron to a custom icon using the following:
- Fork the
faq-accordioncard and modify thetemplate.hbsfile to includeiconUrlrather thaniconName. It should look like this:
<div class="HitchhikerFaqAccordion-icon js-HitchhikerFaqAccordion-icon{{#if card.isExpanded}} HitchhikerFaqAccordion-icon--expanded{{/if}}"
data-component="IconComponent"
data-opts='{"iconUrl": "https://www.brandname.com/themes/simple/images/arrow-down.svg"}'
data-prop="icon">
</div>
- To make the icon rotate like the default chevron does, you will need to add this code to the
answers.scssfile:
.HitchhikerFaqAccordion-icon {
transition: all 400ms ease-in-out;
}
.HitchhikerFaqAccordion--expanded .HitchhikerFaqAccordion-icon {
transform: rotate(-180deg);
}
*Based on the image you're using, you may also need to adjust the icon size.
Here is what the end result will look like:
![]()
Dynamically Access URL Parameters to Use in Cards
Sometimes, brands will want a URL parameter to be dynamically "passed through" to a Search experience. The following will allow you to pull any custom URL parameter(s) from when you initially arrive at the Search results page and append that same parameter to links in the Search experience.
Step 1: Add JavaScript to read and parse the parameter from your URL
Add the following code to your layouts > headincludes.hbs file. By adding the script here you're making it available on every page of your experience.
<script>
function getParameterByName(name, url = window.location.href) {
name = name.replace(/[\[\]]/g, '\\$&');
var regex = new RegExp('[?&]' + name + '(=([^&#]*)|&|#|$)'),
results = regex.exec(url);
if (!results) return null;
if (!results[2]) return '';
return decodeURIComponent(results[2].replace(/\+/g, ' '));
}
var [InternalParamName] = getParameterByName('[ExternalParamName ]');
</script>
Replace ExternalParamName with the name of the actual parameter and InternalParamName with an internal label that you will use to reference the parameter value within your config files.
Say your brand uses a store parameter in the URL that is passed to the search results page, for example:

The user came to the search results page while looking at the website for the Berlin store. To access the parameter store, target it in the last variable declaration like so:
var storeParam = getParameterByName('store');
Step 2: Add parameter variable to your card
Add the parameter variable to your front-end files depending on where you need it. In this case, we will append it to the title link of the product card, in the component.js file, to direct the user to the product page specific to the Berlin store:
return {
title: profile.name,
url: profile.landingPageUrl + '?store=' + storeParam,
...
}
This way, the title URLs going out of the Search experience will include the parameter that was initially passed to the search results page, allowing the brand to close an important analytical loop.

Notes:
- You can access multiple parameters by creating additional variables.
- If the designated parameter is missing from the URL, it will still be appended where specified, just with a null value.
CTAs in Card Structure
Add a Conditional CTA Based on Boolean
You can easily do this by adding a boolean to your component.js file, and modifying the Handlebars template to only show the third CTA if that boolean evaluates to true.
1. Update component.js
The first step is to pass the information about whether a provider is accepting patients. Add an attribute in your component.js file to store whether or not a provider is accepting new patients. If you use the profile field, when this is marked as 'Yes', the boolean will evaluate to true; if it's marked as false or unpopulated, it will evaluate to false.
acceptingNewPatients: profile.acceptingNewPatients,
You'll also need to provide the data mapping for the third CTA.
CTA3: { // The tertiary call to action for the card
label: 'Book Appointment',
iconName: 'calendar',
url: profile.c_primaryCTA.link,
target: '_top',
eventType: 'BOOK_APPOINTMENT',
eventOptions: this.addDefaultEventOptions(),
// ariaLabel: '',
}
2. Update template.hbs
The next step is to use this boolean to only show the tertiary CTA when acceptingNewPatients = true.
We can do this using an if statement in Handlebars. We'll check if card.acceptingNewPatients evaluates to true; if so, we'll add the tertiary CTA. You can see the modifications to the CTA partial below:
{{#*inline 'ctas'}}
{{#if (any (all card.CTA1 card.CTA1.url) (all card.CTA2 card.CTA2.url)(all card.CTA3 card.CTA3.url))}}
<div class="HitchhikerLocationStandard-ctasWrapper">
{{> CTA card.CTA1 ctaName="primaryCTA" }}
{{> CTA card.CTA2 ctaName="secondaryCTA" }}
{{#if card.acceptingNewPatients}}
{{> CTA card.CTA3 ctaname="tertiaryCTA"}}
{{/if}}
</div>
{{/if}}
{{/inline}}
This will hide the CTA if acceptingNewPatients is not populated or false, and show it if it's true.
Add Image CTAs to a Card
In the following example, we add the Apple App Store and Google Play Store buttons to a single FAQ card in lieu of regular CTAs. These buttons are images that link users to the apps to download. You can use this code snippet for any image CTAs you would like to use.
There are a few ways to do this. Since we are using the same two images (one for Apple App Store and one for Google Play Store) for every entity, the recommended approach we'll walk through below is to add a conditional field in the Knowledge Graph. If it's a "Yes", then add the images to the card.
Note: If you would like to use different images per entity, you can add an image field to the Knowledge Graph instead of a Yes/No field and check whether the image has a value before using it. If you want every entity to have an image, you can use placeholder images for any entity missing data (example). In any case, make sure to use a null check so that the data mapping does not error if the image is empty.
- Create a Yes/No field in the Knowledge Graph and call it something like
c_appCTA. - In the
component.jsfile for the relevant card, add a data mapping for anappCTAproperty to thec_appCTAfield you just added, like so:
return {
...
appCTA: c_appCTA,
CTA1: {}
...
}
- In the card's
template.hbsfile, add the new CTAs within a null check within the inline details of the card. Replace the HREF links to direct to the appropriate URLs for your apps. If you need to add more images, simply duplicate theapp-divdiv class.
{{#if card.appCta}}
<div class="HitchhikerFaqAccordion-appCTA">
<div class="app-div">
<a href="https://hitchhikers.yext.com/login" class="app appStoreLink" target="_blank" style="outline: 0px;">
<img class="app-img" src="https://assets.sitescdn.net/landingpages/modules/app_download/images/app-store.svg" alt="app store image">
</a>
</div>
<div class="app-div">
<a href="https://hitchhikers.yext.com/login" class="app google-play" target="_blank" style="outline: 0px;">
<img class="app-img" src="https://assets.sitescdn.net/landingpages/modules/app_download/images/google-play.svg" alt="google play store image">
</a>
</div>
</div>
{{/if}}
The full result would appear as follows:


Add Two Sets of Image CTAs
Continuing the example, say you want to have two sets of these buttons, one for tablet apps and one for mobile apps. You can add some text to differentiate each set and duplicate the CTA divs like so. Be sure to update the link URLs.
{{#if card.appCta}}
<div class="HitchhikerFaqAccordion-appCTAContainer">
<div class="HitchhikerFaqAccordion-appCTAWrapper">
<div class="HitchhikerFaqAccordion-appCTAText">
Tablet App:
</div>
<div class="HitchhikerFaqAccordion-appCTA">
<div class="app-div">
<a href="https://hitchhikers.yext.com/login" class="app appStoreLink" target="_blank" style="outline: 0px;">
<img class="app-img" src="https://assets.sitescdn.net/landingpages/modules/app_download/images/app-store.svg" alt="app store image">
</a>
</div>
<div class="app-div">
<a href="https://hitchhikers.yext.com/login" class="app google-play" target="_blank" style="outline: 0px;">
<img class="app-img" src="https://assets.sitescdn.net/landingpages/modules/app_download/images/google-play.svg" alt="google play store image">
</a>
</div>
</div>
</div>
<div class="HitchhikerFaqAccordion-appCTAWrapper">
<div class="HitchhikerFaqAccordion-appCTAText">
Smartphone App:
</div>
<div class="HitchhikerFaqAccordion-appCTA">
<div class="app-div">
<a href="https://hitchhikers.yext.com/login" class="app appStoreLink" target="_blank" style="outline: 0px;">
<img class="app-img" src="https://assets.sitescdn.net/landingpages/modules/app_download/images/app-store.svg" alt="app store image">
</a>
</div>
<div class="app-div">
<a href="https://hitchhikers.yext.com/login" class="app google-play" target="_blank" style="outline: 0px;">
<img class="app-img" src="https://assets.sitescdn.net/landingpages/modules/app_download/images/google-play.svg" alt="google play store image">
</a>
</div>
</div>
</div>
</div>
{{/if}}
Then horizontally align each pair of CTAs in the answers.scss file with:
.HitchhikerFaqAccordion-appCTA {
display: flex;
}

Result Card Styling
The following code snippets cover examples of styling result cards.
For code snippets on changing the structure of result cards, see the Result Card Structure section above.
Box Shadow Around Card on Hover
Add the following to the answers.scss file:
.[[card name]] {
transition: box-shadow 0.3s;
&:hover {
box-shadow: 0 0 11px rgba(33, 33, 33, 0.2);
}
}

Universal Search Results with Only Top and Bottom Borders
Add the following to the answers.scss file:
.HitchhikerResultsStandard-title {
border-left: none;
border-right: none;
border-top: none;
border-bottom: 1px solid #c5bbb1;
}
.HitchhikerResultsStandard-titleLabel {
border-left: none;
border-right: none;
border-top: none;
border-bottom: none;
}
.HitchhikerResultsStandard-Card {
border-left: none;
border-right: none;
border-top: none;
border-bottom: 1px solid #c5bbb1;
padding-bottom: 30px;
padding-top: 7px;
}
.HitchhikerResultsStandard-viewMore {
border-left: none;
border-right: none;
border-bottom: none;
border-top: none;
}
.yxt-Card {
border-left: none;
border-right: none;
border-top: none;
border-bottom: 1px solid #c5bbb1;
}

Prominent Image Unification
The object-fit properties help define the behavior of the image if it isn't inherently the fixed dimensions.
Add the following to the answers.scss file:
.HitchhikerProductProminentImage-imgWrapper {
justify-content: center;
padding: 0.5rem;
}
.HitchhikerProductProminentImage-img {
width: auto;
height: 200px;
object-fit: cover;
object-position: center;
}
This will standardize your images to all have a height of 200px, with a .5rem border around your images.
Add Circular Headshots
The best way to accomplish this is to do so via the object-fit property. Learn more about this property here.
The below CSS would make the images circular, focusing on the center of the image, with a standard size.
Add the following to the answers.scss file:
.HitchhikerProductProminentImage-img {
width: 100%;
height: 200px;
object-fit: cover;
object-position: center;
border-radius: 50%;
padding: 1rem;
}
If you would like to differentiate certain properties for the Desktop and Mobile experiences you can use media queries:
.HitchhikerProductProminentImage-img {
width: 100%;
height: 200px;
object-fit: cover;
object-position: center;
border-radius: 50%;
padding: 1rem;
@media only screen and (max-width: 768px) {
border-radius: 0px;
padding: 0px;
}
}
Display a List without Bullets
You will utilize list-style-type to display a list on cards and exclude the bullet points.
Add the following to the answers.scss file:
.HitchhikerMenuItemStandard-listItems {
list-style-type: NONE;
}
Center CTAs Vertically
With the default Handlebars template, the CTAs container will align with the details container on a card. If you'd like to change the alignment, you'll need to modify the card template slightly.
If you want to shift the CTAs up to align them vertically within the card, rather than align them with the details container, you can move the title and subtitle into the 'info' div.
1. Update template.hbs
<div class="HitchhikerProfessionalStandard {{cardName}}">
{{> image }}
<div class="HitchhikerProfessionalStandard-body">
<div class="HitchhikerProfessionalStandard-contentWrapper">
<div class="HitchhikerProfessionalStandard-info">
{{> title }}
{{> subtitle }}
{{> details }}
{{> list }}
{{> phone }}
</div>
{{> ctas }}
</div>
</div>
</div>
2. Add Styling
You can ensure the contentWrapper div extends the whole height of the card, and use justify-content and align-self to align the CTAs to the middle of the card.
Add the following to the answers.scss file:
.HitchhikerProfessionalStandard-contentWrapper {
height: 100%;
}
.HitchhikerProfessionalStandard-ctasWrapper {
justify-content: center;
align-self: center;
}
Fix CTAs to Bottom of Card
An easy way to make sure the CTAs are fixed to the bottom of the card is to use Flexbox to our advantage.
Assuming you're using the product-prominentImage card (or a forked version of it), add the following to the answers.scss file:
.HitchhikerProductProminentImage {
&-body {
height: 100%;
display: flex;
flex-direction: column;
}
&-contentWrapper {
height: 100%;
justify-content: space-between;
}
}
This accomplishes the following:
- Specifies the
.HitchhikerProductProminentImage-bodyclass to useflexand take up the full height of the card available after the image - Allows the
.HitchhikerProductProminentImage-contentWrapperclass to take up the full height of the container, and specifies the spacing between the description & the CTAs to bespace-between, forcing the CTAs to the end of the card.
If you don't have a description, the following CSS may help you as it will set the top margin to fix the CTAs container to the bottom of the card.
.HitchhikerProductProminentImage-ctasWrapper {
margin-top: auto;
}
Add Dynamic Text Highlighting to a Result Card
When a user inputs a query and Search finds that a certain field is highlighted, that information can be displayed on result cards with the isHighlighted utility function and highlightField formatter.
When you add these to a card, users will see text formatted as "[[field name]]" mentions [[highlighted text]]. For example, if a users searches "Pulitzer Prize" to see which authors have received that award, any authors that are returned will have text on their result card noting that the text in the query matches data in the awards field.

This is to cover the cases where you have keyword search or document search on a field, but it's not displayed on your card by default.
To do this:
- Create a custom card where you'd like the dynamic highlighting displayed. If you have a custom card already created that you want to add this to, then move to the next step.
- In the card's component.js file, navigate to
dataForRenderobject and add the followingdynamicHighlightsvariable:
//check if "c_awards" is highlighted
var dynamicHighlights = [];
if (HitchhikerJS.isHighlighted("c_awards", profile.d_highlightedFields)) {
const fullHighlight = profile.d_highlightedFields["c_awards"];
dynamicHighlights.push({
"fieldName": "Awards",
"value": Formatter.highlightField(fullHighlight.value, fullHighlight.matchedSubstrings)
});
}
- If you want to check a different field for text matches to highlight, you will update the references to "c_awards" in the code block as well as update
fieldName. For example, if you want to return text from thenamefield, you would use the following:
var dynamicHighlights = [];
if (HitchhikerJS.isHighlighted("name", profile.d_highlightedFields)) {
const fullHighlight = profile.d_highlightedFields["name"];
dynamicHighlights.push({
"fieldName": "Name",
"value": Formatter.highlightField(fullHighlight.value, fullHighlight.matchedSubstrings)
});
}
- List fields also work very similarly. Instead, you'd need to iterate through the items before adding them to your
dynamicHighlightsarray. Here's an example of adding dynamic highlights with the "Languages" built-in field:
if (profile.d_highlightedFields["languages"]) {
const fullHighlight = profile.d_highlightedFields["languages"];
for (const item in fullHighlight) {
if (fullHighlight[item].matchedSubstrings && fullHighlight[item].matchedSubstrings.length > 0) {
dynamicHighlights.push({
"fieldName": "Languages",
"value": Formatter.highlightField(fullHighlight[item].value, fullHighlight[item].matchedSubstrings)
});
}
};
}
- In the same component.js file, add a new property,
highlightedField, to the return statement. Set it up to reference the newdynamicHighlightsvariable you just created:
highlightedField: dynamicHighlights,
When it is complete, the dataForRender in your component.js should look something like this:
dataForRender(profile) {
//check if "c_awards" is highlighted
var dynamicHighlights = [];
if (HitchhikerJS.isHighlighted("c_awards", profile.d_highlightedFields)) {
const fullHighlight = profile.d_highlightedFields["c_awards"];
dynamicHighlights.push({
"fieldName": "Awards",
"value": Formatter.highlightField(fullHighlight.value, fullHighlight.matchedSubstrings)
});
}
return {
title: profile.name, // The header text of the card
url: profile.website || profile.landingPageUrl,
target: '_top', // If the title's URL should open in a new tab, etc.
titleEventOptions: this.addDefaultEventOptions(),
details: profile.description, // The text in the body of the card
highlightedField: dynamicHighlights, //new
showMoreDetails: {
showMoreLimit: 750, // Character count limit
showMoreText: 'Show more', // Label when toggle will show truncated text
showLessText: 'Show less' // Label when toggle will hide truncated text
}
};
}
- Now add the highlights to the card's template.js file. Start by adding this code to the bottom of the file:
{{#*inline 'highlightedField'}}
{{#if card.highlightedField}}
<ul class="highlights">
{{#each card.highlightedField}}
<li class="highlight">"{{this.fieldName}}" mentions {{{this.value}}}</li>
{{/each}}
</ul>
{{/if}}
{{/inline}}
{{!-- other partials below --}}
- At the top of your file, there is a code block with the structure of the card. You will see things like title, subtitle, and details in the order that appear on the card. Add
{{> highlightedField}}in the position you want it to display on the card. In most cases you will want to add it below the{{> details}}like so:
<div class="HitchhikerStandard {{cardName}}">
{{> image }}
<div class="HitchhikerStandard-body">
{{> title }}
{{> subtitle }}
<div class="HitchhikerStandard-contentWrapper">
<div class="HitchhikerStandard-info">
{{> details }}
{{> highlightedField }}
</div>
{{> ctas }}
</div>
</div>
</div>
CTA Styling
The following code snippets cover examples of styling CTAs.
For code snippets on changing the structure of CTAs, including adding them to result cards, see the CTAs in Card Structure section above.
Invert Colors
You may want to emphasize CTAs by inverting the colors (white text on a color background, rather than color text on a white background). You can do so by updating color and background-color attributes on items with class HitchhikerCTA. We've also added some padding so it looks good on desktop and mobile.
.HitchhikerCTA{
color: white;
background-color: #0f70f0;
padding: 4px 8px;
}

Underline Color on Hover
To customize the color of the underline on your CTA to be different than the text color, you will update the property text-decoration-color.
.HitchhikerCTA {
&:hover{
text-decoration-color: black;
}
}

Color Fill on Hover
The following code sets the background color as a linear gradient with a hard line between colors and then enlarges/stretches it using background-size. Then the gradient shifts from one side of the CTA to the other based on the changing background-position from the CTA object to the hover state. Lastly, transition adjusts the time it takes for the linear gradient to fully shift position.
If you want to also change the text color as the CTA fills, you will need to add a hover state to the CTA icon label.
.HitchhikerCTA {
border-radius: 30px;
border: 1px solid #ddd;
background: linear-gradient(to right, #1b64b9 50%, #fff 50%);
background-size: 200% 100%;
background-position: right bottom;
transition: all .3s ease-out;
padding: 10px;
margin: 3px;
color: #1b64b9;
&:hover{
background-position: left bottom;
text-decoration: none;
color: white;
}
}

Diffused Border on Hover
To get this effect, you will first need to create a solid border around the CTA. Then you will add a box-shadow to the hover state to create that diffused look surrounding the border. The first portion of the box-shadow is inset, which affects how much the color diffuses/casts a shadow inward towards the CTA label. The second portion affects how much the shadow casts outward.
You can toggle with the box-shadow depending on how large and opaque you want the diffused border to be.
.HitchhikerCTA {
border: 1px solid black;
&:hover {
box-shadow: 0 0 6px 0 black inset, 0 0 10px 1px black;
}
}

Multicolor Border
.HitchhikerCTA {
border: 3.5px solid;
border-image: linear-gradient(to right, yellow, red , orange , green) 1;
}

Curved Multicolor Border with Filled Hover State
.HitchhikerCTA {
background-image: linear-gradient(to right, red, orange);
border: solid 3px transparent;
border-radius: 20px;
box-shadow: 2px 1000px 1px #fff inset;
padding: 7px;
margin: 5px;
color: red;
&:hover{
box-shadow: none;
color: white;
}
}

Styling Specific CTAs
Sometimes, you might want to style your CTAs differently depending on the card you're using. You can use the parent/child relationships in the HTML of the cards to help target specific CTA classes, so you can modify CTAs in different verticals.
.restaurant .HitchhikerCTA {
color: white;
background-color: black;
padding: 1rem;
}
.event-standard .HitchhikerCTA {
color: black;
border: 1px solid black;
padding: 1rem;
}

You can also style CTAs within a vertical by targeting the primary, secondary, or tertiary CTA.
.HitchhikerEventStandard-primaryCTA .HitchhikerCTA {
color: green;
}
.HitchhikerEventStandard-secondaryCTA .HitchhikerCTA {
color: black;
}

Custom CTA Icon
Typically, the icon associated with the CTA on a result card is defined through the iconName parameter within the CTA, using one of the built-in icons from the icon library. However, if you wish to use a custom image as the CTA icon, you can do so by defining the iconUrl parameter.
When working in the Code Editor, you will update the component.js file of the CTA you want to modify:
CTA1: { // The secondary call to action for the card
label: 'UberEats',
iconUrl: 'https://www.logolynx.com/images/logolynx/32/32ea592d61673edf18f39f3d8f9c1d4f.png',
url: profile.c_uberEatsURL,
target: '_top',
eventType: 'CTA_CLICK',
eventOptions: this.addDefaultEventOptions(),
// ariaLabel: '',
}
![]()
Text Wrapping for Long CTA Labels
There are situations where you might want to wrap CTAs for a specific vertical if they are particularly long. This could be both from a UI perspective but also to create cleaner experiences on mobile.
The key property to do this is white-space, which specifies how white-space inside an element is handled. You can then use text-align to specify how you want the text to be aligned (to the left, centered, or to the right) within the CTA. If nothing is specified, the text will be centered by default.
.HitchhikerCTA-iconLabel {
white-space: normal;
text-align: left
}

Align CTAs Horizontally
For card types that have CTAs stacked vertically (e.g., faq-accordion) by default, you can update them to appear next to each other.
.HitchhikerFaqAccordion-ctasWrapper {
flex-direction: row;
justify-content: space-evenly;
display: flex;
}
You may want to update the width of the buttons to fill up more of the space on the card.
We recommend you test this on mobile though, and make sure it's appearing as desired. You might want to make sure the CTAs are flex-direction: column on smaller breakpoints.

Logo
Search Bar Integration
Replace Search Bar Logo
If you would like to replace the Yext logo when integrating the search bar on your site, you have the option of using a built-in icon from our library or using your own icon. To do so, add one of the following to the addComponent call to initialize the search bar:
-
submitIcon: "magnifying_glass"— ThesubmitIconproperty allows you to use a built-in icon from our library that you loaded. If you use an icon, we recommend choosing the magnifying glass to indicate to users this is a search bar, but you can choose any built-in icon you want to use. -
customIconUrl: "static/assets/images/icon-arrow-right.svg"— ThecustomIconUrlproperty allows you to add a custom icon. Update the value to the URL the image is at. You can either use a URL or reference an image you've uploaded to your site.
Here's what the addComponent call will look like:
ANSWERS.addComponent("SearchBar", {
container: ".search_form",
name: "search-bar", //Must be unique for every search bar on the same page
redirectUrl: "REPLACE_ME_SEARCH_RESULT_URL",
placeholderText: "Search...",
submitIcon: 'magnifying_glass' // Choose a built-in icon
});
Or
ANSWERS.addComponent("SearchBar", {
container: ".search_form",
name: "search-bar", //Must be unique for every search bar on the same page
redirectUrl: "REPLACE_ME_SEARCH_RESULT_URL",
placeholderText: "Search...",
customIconUrl: "static/assets/images/icon-arrow-right.svg" // Choose an icon from an image URL
});
This result will look something like this:

To learn more about Search Bar integration and optional styling, you can follow this guide.
Overlay & Search Results Page — Search Bar
Replace Search Results Logo
To replace the Yext logo in the overlay and/or the search bar on the search results page, update the frontend of your Search experience in the Code Editor. Edit the componentSettings.SearchBar component within the config file for ALL pages you have displayed in the overlay (e.g., index.json, jobs.json, etc.) or want to edit the search bar on. Similar to a search bar you will add either:
-
submitIcon: "magnifying_glass"— allows you to use a built-in icon from our library. -
customIconUrl: "static/assets/images/icon-arrow-right.svg"— allows you to add a custom icon. Update the value to the URL the image is at.
This is what the componentSettings.SearchBar should look like:
"SearchBar": {
"placeholderText": "Search", // The placeholder text in the answers search bar
"allowEmptySearch": true,
"submitIcon": "magnifying_glass" // Choose a built-in icon
},
Or
"SearchBar": {
"placeholderText": "Search", // The placeholder text in the answers search bar
"allowEmptySearch": true,
"customIconUrl": "static/assets/images/icon-arrow-right.svg" // Choose an icon from an image URL
},
The search bar on the results page will look like this:

And the overlay will look something like this:

Search Results Page — Footer
Remove Footer Logo
To remove the logo on the search results page, you will need to comment out the yext-logo layout within all vertical .html.hbs files and the index.html.hbs file:
<div class="Answers-footer">
{{!-- {{> layouts/yext-logo }} --}} //Comment out to remove the logo
{{> templates/vertical-standard/markup/locationbias }}
</div>
This will remove the logo at the bottom of the experience:

Change Logo Color
To make the Yext logo match your branding, you may need to change its color. The built-in black logo works well for a light background, but if you have a dark background, you may want to use our white logo. To do so, add CSS in the answers.scss file to invert the color of the logo to white.
.Answers-footerLogo {
filter: invert(100%);
}
Replace Footer Logo
To use a different logo completely, you can upload an image to the Code Editor (or use an existing image online) and update the logo image source.
- Save the new logo in the Code Editor
static > assets > imagesfolder. - Override theme. Click on Tools > Jambo Commands > Override Theme. Select
layouts/yext-logo.hbs. - Replace the yext-logo image asset with a new image tag. The file should look like:
<a class="Answers-footerLink"
href="https://www.yext.com/get"
target="_blank"
rel="nofollow noopener noreferrer"
aria-label="Visit yext.com">
<img src="static/assets/images/view.png"
class="Answers-footerLogo"
alt="Visit yext.com">
</a>
- If you use your brand's logo, you may want to update the links and alternate texts to reference your own website.
- If you don't want to add a link to the logo, you can remove the anchor tag.
- Optionally edit the CSS to get the appropriate sizing. You must reference
.Answers-footerLinkoutside of the.Answersobject.
.Answers-footerLink {
width: 30px;
height: 30px;
}
Custom Formatters
Format Boolean Value to Display on Card
In order to "transform" the boolean field, we recommend using a custom (yet simple) JS formatter in your static > js > formatters-custom.js file.
Here, you can add the following code within the file:
export function acceptingStatus(profile) {
if (profile.acceptingNewPatients) {
return "Accepting New Patients";
}
return "";
}
This formatter translates the "TRUE" boolean value in the acceptingNewPatients field to "Accepting New Patients".
From here, update the details mapping within your card's component.js file to transform the data using your JS formatter:
details: Formatter.acceptingStatus(profile),
Add a Bulleted List of Call to Action Links
-
Add the below function to the
static/js/formatters-custom.jsfile:
export function listCTA(list) {
if (!list) {
return null;
}
let names = [];
list.forEach((element) =>
names.push(
`<a href="${Formatter.generateCTAFieldTypeLink(element)}">
${element.label}
</a>`
)
);
return names;
}
- Use the formatter in a 'list' section on your card.
Replace c_contactLinks with the field you want to display.
listItems: Formatter.listCTA(profile.c_contactLinks);
- Update the Handlebars template to display the HTML.
To allow the HTML to display on the page, we need to ensure the Handlebars template treats it correctly. We do this by ensuring the element is surrounded by three braces {{{ }}}.
Specifically ensure the listItems field looks like the following:
{{#each card.listItems}}
{{{this}}}
{{/each}}
Add a Bulleted List of Linked Entity Names
If you want to add a list of the names in an entity relationship field (for example, a list of Linked Ingredients on a Recipe card), you'll need to use a formatter to extract an array of names from the linked entity objects.
1. Add the below function to the static/js/formatters-custom.js file.
The syntax of the formatter will depend on the version of the theme you're on. Take a look at the formatters in the theme/static/js/formatters-internal.js file if you are unsure.
export function listNames(entityList) {
if (!entityList) {
return null;
}
let names = [];
entityList.forEach((element) => names.push(element.name));
return names;
}
2. Use the formatter in a 'list' section on your card.
Replace c_ingredients with the field you want to display.
listItems: Formatter.listNames(profile.c_ingredients),
Adding Reopen Dates & Temporary Closures
1. Add the below to the static/js/formatters-custom.js file.
export function reopenStatus(profile) {
if (profile.hours && profile.hours.reopenDate) {
return "This location is temporarily closed";
} else {
return "This location is operating under normal business hours";
}
}
2. Add the below to the card's component.js file
subtitle: Formatter.reopenStatus(profile),

Date Formatter Function
If you want to return the month as a number ("11") instead of long-form ("November"), just change the final return statement to "numeric".
import {
_getDocumentLocale,
_getProfileFieldAtKeyPath
} from './formatters-internal.js';
export function longDate(profile, keyPath) {
const dateString = _getProfileFieldAtKeyPath(profile, keyPath);
if (!dateString) {
return '';
}
const parsedDateString = dateString + 'T00:00:00';
const date = new Date(parsedDateString);
const locale = _getDocumentLocale();
if (!dateString) {
return '';
} else {
return {
day: date.toLocaleString(locale, {day: 'numeric'}),
month: date.toLocaleString(locale, { month: 'long'}),
year: date.toLocaleString(locale, {year: 'numeric'}),
}
}
}
This function returns an object with three components: "day", "month" and "year". You can then call the function and reference each of the components when concatenating them together. For example, the following would give "Month Day, Year":
subtitle: profile.c_startDate ? Formatter.longDate(profile, "c_startDate").month + " " + Formatter.longDate(profile, "c_startDate").day + ", " + Formatter.longDate(profile, "c_startDate").year : null,
If you change the month to numeric at the end of the formatter function, you can return the date in the format "mm/dd/yyyy" using:
subtitle: profile.c_startDate ? Formatter.longDate(profile, "c_startDate").month + "/" + Formatter.longDate(profile, "c_startDate").day + "/" + Formatter.longDate(profile, "c_startDate").year : null,
Subdomain Header & Footer
If you are pursuing a Subdomain Search integration, then you'll want to add a header and footer to the experience to create a seamless user experience for your site visitors. There are two handlebars files that control the header and footer, which can be found in your layouts folder — header.hbs and footer.hbs.

Let's look at the header file. When you open the file, you'll see the below:
{{!-- <div class="Header"></div> --}}
You can simply uncomment this line and add your HTML within the Header div.
Note: Modifying headers and footers requires a good understanding of HTML and JS. Make sure that you test any of your changes across all browsers and breakpoints.
Header Example
We'll need to make updates to both the html of the header in the header.hbs file, and add css in the answers.scss file to style it. We'll walk through the HTML and CSS required to create a simple header like the one pictured below.
Desktop

Mobile

layouts/header.hbs
Here, we'll create a simple header with an image on the left, and links on the right. The classes added will help us style these different containers separately later on.
<div class="Header">
<div class="Header-left">
<img src="https://dynl.mktgcdn.com/p-sandbox/FVCnI4EXZe3nj2hzKvJLgzIbTZ4YWRmYZCMvdjlXGR0/3000x3000.png"/>
</div>
<div class="Header-right">
<ul class="header-links">
<li class="header-link"><a href="https://turtleheadtacos.com/home">Home</a></li>
<li class="header-link"><a href="https://turtleheadtacos.com/menu">Menu</a></li>
<li class="header-link"><a href="https://turtleheadtacos.com/jobs">Jobs</a></li>
<li class="header-link"><a href="https://turtleheadtacos.com/contact">Contact</a></li>
</ul>
</div>
</div>
answers.scss
.Header {
display: flex;
justify-content: space-between;
background-color: #EFF0D2;
align-items: center;
img {
margin-left: 2rem;
max-height: 75px;
}
.header-links {
display: flex;
align-items: center;
}
.header-link {
margin: 1rem;
font-weight: bold;
text-transform: uppercase;
&:hover {
text-decoration: underline;
}
}
}
@media only screen and (max-width: 576px) {
.Header {
flex-direction: column;
img {
margin-left: 0;
}
}
}
Footer Example
Adding a footer will be the same process we followed above for the header.

layouts/footer.hbs
Here, we'll add two sections — one for the copyright text, and one for the links.
<footer class="Footer">
<div class="footer-copywright">© 2020 Turtlehead Tacos Inc.</div>
<ul class="footer-links">
<li class="footer-link"><a href="https://turtleheadtacos.com/privacy-policy">Privacy Policy</a></li>
<li class="footer-link"><a href="https://turtleheadtacos.com/contact-us">Contact Us</a></li>
</ul>
</footer>
answers.scss
.Footer {
display: flex;
padding: 1rem;
border-top: 1px solid #dcdcdc;
justify-content: space-between;
.footer-links {
display: flex;
flex-direction: row;
}
.footer-link {
text-decoration: underline;
margin: 0 1rem;
&:hover {
text-decoration: none;
}
}
}