Card Layout | Yext Hitchhikers Platform
What You’ll Learn
In this section, you will learn:
- How to modify a card layout
- Common changes to cards
Customizing Card Layout
Because data is inherently different customer to customer, there may be situations where you want to modify the layout and structure of our standard cards. To do this, you’ll need to fork a card, which you learned in the
Adding Pages and Cards units
, which allows you to override the component.js
and template.hbs
files.
Example 1: Adding a Third CTA
There may be cases where you want to feature a third CTA on your card; for example, you might want a ‘View Menu’ CTA in addition to ‘Call’ and ‘Get Directions’ on a Restaurant card.
This will require changes to three files:
- component.js to add an additional CTA to the data mappings
- template.hbs to indicate in the template to pull from this data
- answers.scss to apply the same styling to the third CTA as the first and second CTA
component.js
Just like we have objects defining CTA1 and CTA2, we’ll add a third object, CTA3, with the same attributes.
CTA1: { // The primary call to action for the card
iconName: 'phone', // The icon to use for the CTA
label: 'Call', // The label of the CTA
url: Formatter.phoneLink(profile), // The URL a user will be directed to when clicking
target: '_top', // If the URL will be opened in a new tab, etc.
eventType: 'TAP_TO_CALL', // Type of Analytics event fired when clicking the CTA
eventOptions: this.addDefaultEventOptions(), // The analytics event options for CTA clicks
},
CTA2: { // The secondary call to action for the card
label: 'Get Directions',
iconName: 'directions',
url: Formatter.getDirectionsUrl(profile),
target: '_top',
eventType: 'DRIVING_DIRECTIONS',
eventOptions: this.addDefaultEventOptions(),
},
CTA3: { // The tertiary call to action for the card
label: 'View Menu',
iconName: 'info',
url: profile.menuUrl ? profile.menuUrl.url : null,
target: '_top',
eventType: 'CTA_CLICK',
eventOptions: this.addDefaultEventOptions(),
}
template.hbs
Next, you’ll add the third card CTA where the other two CTAs are referenced. By adding {{> CTA card.CTA3 ctaName="tertiaryCTA" }}
in the CTAs partial, you’re indicating that a third cta be added after the primaryCTA and secondaryCTA are added, and that it should pull from the data found in card.CTA3 (which you defined in your component.js file!).
You also will need to check if the data exists in the CTA3 field before trying to place the CTA on the page - you can do this by adding (all card.CTA3 card.CTA3.url)
to the if statement.
{{#*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" }}
{{> CTA card.CTA3 ctaName="tertiaryCTA" }}
</div>
{{/if}}
{{/inline}}
answers.scss
Lastly, you want to make sure that the styling is consistent. The following CSS copies the styling from .HitchhikerLocationStandard-primaryCTA
and .HitchhikerLocationStandard-secondaryCTA
and adds .HitchhikerLocationStandard-tertiaryCTA
so that those style rules apply. This may change based on the card you fork from, so always inspect the styling in order to determine the style rules you should copy.
.HitchhikerLocationStandard-primaryCTA, .HitchhikerLocationStandard-secondaryCTA, .HitchhikerLocationStandard-tertiaryCTA {
display: flex;
margin-top: calc(var(--hh-location-standard-base-spacing) / 2);
}
Example 2: Adding a Secondary Bulleted List
Here’s an example of adding a second list to a card. We’ll walk through adding a “Nutritional Claims” list by forking the menuitem-standard card, and moving the lists to display underneath the menu item description.
component.js
First, we’ll copy the way that we map the data for the existing list, and add listTitle2
and listItems2
to our data mappings so the field data is accessible to our template.
listTitle2: 'Nutritional Claims',
listItems2: profile.c_nutritionalClaims,
template.hbs
Next, we’ll update the template to accomodate this new data.
Defining the List Partial
First, we’ll copy the existing list partial, and modify it for our new list through the following actions.
- Update the name of the partial to ‘list2’
- Update the
card.
references to point tocard.listTitle2
andcard.listItems2
Add a class ‘nutritionalClaims’ in case we want to add specific styling to this list later on.
{{#*inline 'list2'}} {{#if (any card.listTitle2 card.listItems2)}} <div class="HitchhikerMenuItemStandard-listWrapper nutritionalClaims"> {{#if card.listTitle2}} <div class="HitchhikerMenuItemStandard-listTitle"> {{card.listTitle2}} </div> <ul class="HitchhikerMenuItemStandard-listItems"> {{#each card.listItems2}} <li class="HitchhikerMenuItemStandard-item"> {{this}} </li> {{/each}} </ul> {{/if}} </div> {{/if}} {{/inline}}
Referencing the new Partial
Afterwards, we’ll reference the partial {{> list2 }}
in order to display this on the card. In order to style the lists separately, we’re containing these two lists in a div
with a class of HitchhikerMenuItemStandard-lists
. We also can move the {{> details }}
partial above our new Lists container so it displays above the lists.
<div class="HitchhikerMenuItemStandard {{cardName}}">
{{> image }}
<div class="HitchhikerMenuItemStandard-body">
{{> title }}
{{> subtitle }}
<div class="HitchhikerMenuItemStandard-contentWrapper">
<div class="HitchhikerMenuItemStandard-content">
{{> details }}
<div class="HitchhikerMenuItemStandard-lists">
{{> list }}
{{> list2 }}
</div>
</div>
{{#if (any (all card.CTA1 card.CTA1.url) (all card.CTA2 card.CTA2.url))}}
<div class="HitchhikerMenuItemStandard-ctasWrapper">
{{#with card.CTA1}}
{{> CTA ctaName="primaryCTA" }}
{{/with}}
{{#with card.CTA2}}
{{> CTA ctaName="secondaryCTA" }}
{{/with}}
</div>
{{/if}}
</div>
</div>
</div>
answers.scss
The below CSS accomplishes a few things:
- Adds styling for
.HitchhikerMenuItemStandard-detailsText
to add some space below the details and above the lists - Adds styling for
.HitchhikerMenuItemStandard-lists
to display the two lists next to eachother on larger breakpoints, and stacked on top of eachother for smaller breakpoints (under 768px) - Adds a margin to
.HitchhikerMenuItemStandard-listWrapper
to space out the two lists Adds styling to the list in
.nutritionalClaims
to change the bullets to square instead of disc..HitchhikerMenuItemStandard-detailsText { margin-bottom: 1rem; } .HitchhikerMenuItemStandard-lists { display: flex; } @media only screen and (max-width: 768px) { .HitchhikerMenuItemStandard-lists { display: block; } } .HitchhikerMenuItemStandard-listWrapper { margin-right: 2em; } .nutritionalClaims ul { list-style-type: square; }
Example 3: Adding an Icon next to the Distance Label
You can also add any HTML you want to the card itself, without updating the data mappings. One example might be adding a pin icon next to the distance listed on a location card.
template.hbs
To add the pin, we’ll add in an
SVG
to the template, containing it in a div with a class of HitchhikerLocationStandard-distanceIcon
so we can apply styling later.
{{#*inline 'distance'}}
{{#if card.distance}}
<div class="HitchhikerLocationStandard-distance">
<div class="HitchhikerLocationStandard-distanceIcon">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 14 20"><path d="M7 0C3.13 0 0 3.13 0 7c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7zm0 9.5C5.62 9.5 4.5 8.38 4.5 7S5.62 4.5 7 4.5 9.5 5.62 9.5 7 8.38 9.5 7 9.5z"></path></svg>
</div>
{{card.distance}}
</div>
{{/if}}
{{/inline}}
answers.scss
Below, we’ll add some styling to ensure the location label and the pin display the in the same line, and add specific styling to the icon itself to make sure it displays as we want it to.
.HitchhikerLocationStandard-distance {
display: flex;
}
.HitchhikerLocationStandard-distanceIcon {
height: 1em;
width: 1em;
margin-top: .1rem;
fill: var(--yxt-color-brand-primary);
margin-right: .25rem;
}