Skip to main content
Support

Handlebars Helpers for Custom Templates

If you're building a custom HTML template for your HelpDocs, you'll eventually need to use some of our helpers and partials.

Taylor
Updated by Taylor
8 min read

If you're building a custom HTML template for your HelpDocs, you'll eventually need to use some of our helpers and partials.

Helpers

Helpers are extensions to the regular Handlebars syntax that allow you to manipulate data, loop through arrays, show HTML conditionally, and more. We've made a number of helpers to help you with common tasks.

Using Helpers

There's a few different ways to use helpers:

  1. Inline helpers
    The simplest way to use helpers is inline. e.g.
    {{fallback article.title "Untitled Article"}}
    ...will render literally to the article's title if it exists, falling back to "Untitled Article" if not.
  2. Block helpers
    Block helpers can help you do conditional statements and loops. You prefix the helper name with a hash, and write extra HTML (or even more Handlebars) inside. Then use an else block for when the condition is not true. e.g.

    {{#if article.is_featured}}
    This article is featured!
    {{else}}
    Not featured, sorry :(
    {{/if}}
    ...will render to "This article is featured!" if the article is featured, "Not featured, sorry :(" if not.
  3. Combining helpers
    Need to combine more than one helper? Use brackets! This is super helpful if you wanna display something conditionally, e.g.
    {{#if (gt category.meta.num_articles 1)}}
    This category has more than one article
    {{/if}}
    ...will only show "This category has more than one article" if the category does in fact have more than one article.

Bundled Helpers

Helper Name

Description

Example Usage

if

Only show the content of the block if the condition is true, else show the content of the else block (if it exists)

{{#if article.is_featured}}
<p>Article is featured</p>
{{else}}
<p>Article is not featured</p>
{{/if}}

unless

Opposite of if. Only show the content of the block if the condition is false, else show the content of the else block (if it exists)

{{#unless article.is_private}}
<h1>This is a public article</h1>
{{/unless}}

each

Loop through an array. The current item is provided as this, you can access the root scope with @root, the current index with @index, and use @first and @last to see if this is the first or last item

{{#each category.articles}}
<p>{{this.title}}</p>
<small>{{this.description}}</small>
{{/each}}

eq

Checks if two values are equal. They need to be the same type, so the result of a math helper like add won't equal a plain number

{{#if (eq this.meta.num_articles 1)}}
There's one article in this category
{{/if}}

gt

Checks if the first number is greater than the second. It only takes whole numbers, so passing it the result of a math helper like divide stops the page rendering

{{#if (gt this.meta.num_articles 1)}}
There's more than one article in this category
{{/if}}

lt

Checks if the first number is less than the second. Like gt, it only takes whole numbers

{{#each this.articles}}
{{#if (lt @index 5)}}
<img src="{{this.author.profile_image}}">
{{/if}}
{{/each}}

multiply

Multiplies two numbers together

<div style="margin-left:{{multiply @index 0.5}}em;"></div>

divide

Divides the first number by the second. Dividing by zero gives 0

Half of these articles: {{divide category.meta.num_articles 2}}

add

Adds two numbers together

This is loop number {{add @index 1}}

subtract

Subtracts the second number from the first

2 - 1 = {{subtract 2 1}}

hasPrefix

Checks if a string starts with a string prefix

{{#if (hasPrefix category.icon "fa-")}}
<i class="fa {{category.icon}}"></i>
{{else if (hasPrefix category.icon "http")}}
<img src="{{category.icon}}">
{{/if}}

hasSuffix

Checks if a string ends with a string suffix

Suffix ends in fix:{{hasSuffix "Suffix" "fix"}}

trimLeft

Removes any of the given characters from the start of a string. It works character by character rather than matching a whole prefix, so a long second value can remove more than you expect

Path without its leading slash: {{trimLeft "/demo" "/"}}

trimRight

Removes any of the given characters from the end of a string. Like trimLeft, it works character by character

Home path without its trailing slash: {{trimRight meta.home_path "/"}}

deepLookup

Behaves like the built-in Handlebars lookup helper, but returns an object of the original type rather than converting to a string

The first article's title is <strong>{{deepLookup (deepLookup category.articles 0) "title"}}</strong>

formatDate

Show a date in a format of your choice.

Supported tokens: D, DD, M, MM, YY, YYYY , hh, mm, and ss.

Premade formats: RFC3339, unix, relative (human readable, English only: other languages get the default D/M/YYYY).

Everything except RFC3339 and unix comes wrapped in a <time> tag.

{{formatDate article.updated_at "DD.MM.YYYY hh:mm:ss"}}

fallback

If the first value exists, returns that. If not, returns the second

{{fallback meta.home_path "/"}}

filterCategoriesByParentId

Used to find all subcategories of a given category ID

{{#each (filterCategoriesByParentId @root.meta.sidebar_categories this.category_id)}}
<h3>{{this.title}}</h3>
{{/each}}

categoryById

Find a category by its ID

This article's category is {{deepLookup (categoryById meta.sidebar_categories article.category_id) "title"}}

categoryIsAscendent

Checks if a category is ascendent of another. Useful when working with subcategories and sidebars

{{#categoryIsAscendent @root.meta.sidebar_categories @root.category this}}
<p>This is a parent of the displayed category</p>
{{/categoryIsAscendent}}

In the example here the second parameter this is also a category. It's checking if the second category is ascendent of the first. A category also counts as its own ascendent.

i18n

Find the current language version of a given internationalization key, falling back to the second string

<button type="button">
{{i18n "contact" "Contact"}}
</button>

page

Only display the contents of a block if the page is equal to the given page. Possible values: categories (your home page), category, article, and search

{{#page "categories"}}
{{> superFancySearchBar}}
{{else}}
{{> boringOlSearchBar}}
{{/page}}

isPermissioned

Shows content of a block if the article has any permissions on it and your plan includes permissions. Requires article to be passed through

{{#isPermissioned article}}
<div class="has_permissions_message">
<span>This article has Permissions and so can't be shared publicly.</span>
</div>
{{/isPermissioned}}

isEmoji

Checks if a string is an emoji. You'll need this if your categories or articles use emoji icons, because they won't show otherwise

{{#if (isEmoji category.icon)}}
  <span>{{category.icon}}</span>
{{else if (hasPrefix category.icon "fa-")}}
  <i class="fa {{category.icon}}"></i>
{{/if}}

categoryDepth

How deep a category is nested, starting at 1 for a top-level category

<div class="depth-{{categoryDepth @root.meta.sidebar_categories this.category_id}}"></div>

json

Outputs a value as JSON, which is handy for passing data to your own JavaScript

<script>
  var languages = {{json meta.languages}};
</script>

urlEncode

Makes a value safe to use in a URL's query string

<a href="https://example.com/?title={{urlEncode article.title}}">Share</a>

withoutQueryString

Removes the query string from a URL

<img src="{{withoutQueryString config.logo}}">
page, categoryIsAscendent, and isPermissioned are block helpers, so use them with a hash like the examples above. Inside an if or unless that has an else, they'll always take the first branch.

The standard Handlebars helpers like with and lookup work too.

You'll see templateOption and featureGate in our starter templates. Custom templates don't have Template Options, so templateOption checks normally do nothing and you can delete them. featureGate checks what's on your plan, so leave those where they are.

Partials

Partials in Handlebars are snippets of HTML we provide for your convenience. Just like the partials you write yourself for the header and footer, these let you use reusable code that we maintain, without the effort.

Using Partials

You can use partials with the Handlebars partial syntax. For instance to create a contact button you can use {{> contactLink}}. That will render a clickable contact link your users can use to contact you.

Because we maintain it, a) you don't have to worry about it, and b) it'll respect any integrations you have set up in your account.

Bundled Partials

Partial Name

Description

Example Usage

contactLink

Contact link that respects any connected integrations and your contact preferences in Settings. The class parameter will add a CSS class to the button of your choice, overriding the default button class applied

{{> contactLink class="btn btn-secondary"}}

categoryBreadcrumbs

Breadcrumbs that lead to your current page. This should be used in the category.hbs and article.hbs content partials only. The linkify parameter indicates whether the last category in the list should be wrapped in a hyperlink (like for an article page) or not (like for a category page). Our V5 templates also pass version="4", which switches the separator to a chevron icon

{{> categoryBreadcrumbs version="4" linkify=true}}

hdFooter

Renders the HelpDocs footer according to the HelpDocs Branding setting in Settings > Customize > Design. We require this to be present on all accounts, but you can include it anywhere you like. If you leave it out we'll add it to the end of your footer. The version parameter gives you the styling of that template generation, and our V5 templates use version="5"

{{> hdFooter version="5"}}

contactModal

The contact form that contactLink opens. Custom templates need to include this themselves, so add it to footer.hbs if you use our contact form. Our V5 templates pass version="4", which adds the form's script

{{> contactModal version="4"}}

feedback

The article feedback block. This should be used in the article.hbs content partial

{{> feedback}}

lazySidebar

Category and article navigation for a sidebar, loaded so that it stays fast on big help centers. Our V5 Bars and Detailed templates use it. You can change its markup with the optional container_id, category_class, article_class, current_class, expanded_class, collapse_class, and collapse_open_class parameters

{{> lazySidebar container_id="my-sidebar"}}

Custom Partials

We support the Handlebars 4 inline partial syntax, so you can make your own partials. This is super handy if you need to do anything recursive (like nesting categories) or repetitive (so you don't have to maintain two lots of the same code).

You can create a custom partial like this:

{{#*inline "myArticle"}}
<h3>{{article.title}}</h3>
<p>{{article.description}}</p>
{{/inline}}

Then invoke it just like you'd invoke any other partial, passing parameters if you like:

{{#each category.articles}}
{{> myArticle article=this}}
{{/each}}

Easy as that!

Inline partials must be at the top level, not indented, and not nested inside any other markup. The opening and closing tags each need their own line. A good place to declare these would be header.hbs.

What did you think of this doc?

Next Getting Started with a Custom HTML Template

Get in touch