Using the help center templating language


What's my plan?

All Suites
Growth, Professional, Enterprise, or Enterprise Plus


Support with
Knowledge Professional or Enterprise

This article covers the following topics:
Introduction
Templating basics
Comments
Block Comments
Literals
Properties
Conditionals
How conditions are evaluated
Trimming white space
Helpers
Changing scope
Passing the root context to a helper
Accessing items in an array
Length
Subexpressions
Introduction Each help center theme consists of a collection of editable page templates that define the layout of different types of pages in help center. For example, there's a template for knowledge base articles, a template for the list of requests, and so on. Each template consists of a mix of HTML markup and Handlebars-like expressions, identifiable in the template by double curly brackets. Handlebars is a simple templating engine that lets you insert or manipulate content on a page at render-time rather than at design-time. The templating language in help center is called Curlybars and implements a large subset of the Handlebars language. This guide shows you how use the language to customize your pages in help center. help center provides you with helpers and named properties to customize your content. Some are shared and available on all help center pages. The rest are page-specific. Example {{#each comments}}
&lt;li class="comment" id="{{comment_id}}"&gt;
&lt;div class="comment-avatar {{#if author.agent}} comment-avatar-agent {{/if}}"&gt;
&lt;img src="{{author.avatar_url}}" alt="Avatar" /&gt;
&lt;/div&gt;

&lt;div class="comment-container"&gt;
&lt;header class="comment-header"&gt;
&lt;strong class="comment-author"&gt;
{{author.name}}
&lt;/strong&gt;
&lt;/header&gt;
&lt;/div&gt;
&lt;/li&gt;
{{/each}}
The example generates a list of users who left comments on the page. The each helper iterates through each value in the page's comments property. For each comment, the values of the author.avatar_url and author.name properties are inserted in the HTML. <!--
title: Using the Help Center templating language
filename: using_curlybars.md
kb: https://support.zendesk.com/hc/en-us/articles/205753348
--> Templating basics This section introduces the building blocks you need to write any template. For more information, see Help Center Templates on developer.zendesk.com. A Curlybars template is made up of two things: verbatim text to be rendered as is, and Curlybars expressions. This implies that an empty template is also a valid template, and a template that contains only text is also a valid one. For instance, the following is a valid template: Article

&lt;p&gt;Some details on the article&lt;/p&gt;
Of course, if help center templates only supported verbatim text, you couldn't really customize them at render-time. To add templating logic, you need Curlybars expressions, which are enclosed double curly brackets({{ and }}). To add templating logic to the previous example, you might modify the template as follows: Article

&lt;p&gt;Some details on the article&lt;/p&gt;

{{article.author.name}}
The following sections explain how to write valid expressions to make meaningful changes to the template. Note that nesting a pair of curlies within other pair of curlies is not valid syntax. For example, the following isn't allowed: Article

&lt;p&gt;Some details on the article&lt;/p&gt;

{{ {{ ... }} }}
Comments There are situations where having some notes in the template that do not leak into the rendered page might come in handy. For this purpose, Curlybars allows to make comments putting an exclamation mark right after the opening curlies, without any space: {{! ... }}. You can use this syntax to add a code comment in the example: {{!
This template aims to
show details of an article
}}

&lt;h1&gt;Article&lt;/h1&gt;

&lt;p&gt;Some details on the article&lt;/p&gt;
Here's what's sent to the browser after the page is rendered: Article

&lt;p&gt;Some details on the article&lt;/p&gt;
This effect of discarding anything within the comments can actually come in handy while developing a template. You might want to comment out some code to do some checks, debug, and more. Block Comments Unfortunately, the comment syntax described so far isn't suitable for commenting out Curlybars code. To comment out Curlybars code, use the following syntax: {{!-- ... ---}}. This kind of comment can span several lines and effectively comment out code. Example: {{!
This template aims to
show details of an article
}}

&lt;h1&gt;Article&lt;/h1&gt;

&lt;p&gt;Some details on the article&lt;/p&gt;

{{!--
I want to commend out the following code:

{{ ... some Curlybars expressions }}

--}}
The template above is rendered as follows: Article

&lt;p&gt;Some details on the article&lt;/p&gt;
Literals To include values that you want Curlybars to interpret exactly as they're written, Curlybars supports the concept of literals. A literal can represent 3 types of values: a string, a boolean, or a number. To express a string, you can use both single and double quotes, but you can't mix them. For example, 'this is a valid string', "this is valid as well", but "this is not valid'. A number can be any positive or negative integer. 123 is a valid positive number, +123 represents the same value, 00123 is still valid, and -123 is valid as well. A boolean is represented by true and false. No other variation is allowed. For example, TRUE and FALSE aren't intepreted as booleans in Curlybars. You can render literals. Example: A string: {{ 'hello world' }}
A boolean: {{ true }}
A number: {{ 42 }}
The page is rendered as follows: A string: 'hello world'
A boolean: true
A number: 42
Properties Every template in the help center has access to a context that represents data about your help center. For instance, the Article Page template has an object named article that exposes the structure of the article requested by the users. For all the properties you can use in your templates, see Help Center Templates on developer.zendesk.com. Use dot notation to pluck a specific information from these objects. A simple example is article.title. The fully qualified name of a property is sometimes called a path. For example, name is a property in the author object, but article.author.name is its path. You can display the value of a property by enclosing it within double curly brackets. Getting back to the example, you might want to print out the name of the author in a separate paragraph: Article

&lt;p&gt;Author: {{article.author.name}}&lt;/p&gt;
Let's say a user wants to see an article written by an agent named John Venturini. The template will be rendered as follows: Article

&lt;p&gt;Author: John Venturini&lt;/p&gt;
You might also want to render the article itself. The article object has a body property that contains the content of the article. You'd modify the template as follows to render the body of the article: Article

&lt;p&gt;Author: {{article.author.name}}&lt;/p&gt;

&lt;article&gt;{{article.body}}&lt;/article&gt;
Conditionals In addition to rendering property values, the templating language lets you add conditional rendering logic to your templates. For instance, you might want to render a snippet of HTML in case the requested article is internal. The Article Page context has an article.internal property that returns true if the article is internal and false otherwise. You can create an if block with this information. The if expression must specify a condition that's true or false. The result determines whether the content in the block is rendered or not. Here's the basic syntax: {{#if condition}}
This is rendered if the condition is true.
{{/if}}
You can modify the example template as follows: Article

{{#if article.internal}}
&lt;p&gt;This article is internal.&lt;/p&gt;
{{/if}}

&lt;p&gt;Author: {{article.author.name}}&lt;/p&gt;

&lt;article&gt;{{article.body}}&lt;/article&gt;
You might want to render a block when the condition is false. In that case, use an unless block. The syntax is similar to the if block: {{#unless condition}}
This is rendered if the condition is false.
{{/unless}}
Back to the example, suppose you also want to render a message when an article is not internal. You can modify the template as follows: Article

{{#if article.internal}}
&lt;p&gt;This article is internal.&lt;/p&gt;
{{/if}}

{{#unless article.internal}}
&lt;p&gt;This is a publicly visible article!&lt;/p&gt;
{{/unless}}

&lt;p&gt;Author: {{article.author.name}}&lt;/p&gt;

&lt;article&gt;{{article.body}}&lt;/article&gt;
This kind of conditional logic -- "if true do this or else do this" -- is usually handled by an if-else block. The syntax is as follows: {{#if condition}}
This is rendered if the condition is true.
{{else}}
This is rendered if the condition is false.
{{/if}}
You can modify the example as follows: Article

{{#if article.internal}}
&lt;p&gt;This article is internal.&lt;/p&gt;
{{else}}
&lt;p&gt;This is a publicly visible article!&lt;/p&gt;
{{/if}}

&lt;p&gt;Author: {{article.author.name}}&lt;/p&gt;

&lt;article&gt;{{article.body}}&lt;/article&gt;
The unless block also has an unless-else variant. You could use it to achieve the same result as an if-else block: Article

{{#unless article.internal}}
&lt;p&gt;This is a publicly visible article!&lt;/p&gt;
{{else}}
&lt;p&gt;This article is internal.&lt;/p&gt;
{{/unless}}

&lt;p&gt;Author: {{article.author.name}}&lt;/p&gt;

&lt;article&gt;{{article.body}}&lt;/article&gt;
How conditions are evaluated A condition is usually a help center property such as article.internal, which has a boolean value of true or false. Some properties don't have boolean values. These properties are evaluated as follows:
If the value is a number, then 0 is false and any other number is true
If the value is a string, an empty string is false and any other string is true
If the value is a collection of objects, an empty collection is false and any other collection is true
If the value is null, the expression is false
Suppose you want to set up some conditional logic that checks numbers. The Article Page has an article.comment_count property that contains the total number of comments in an article. You can use the if condition to test if the count is not 0 and display some cheerful message. Example: Article

&lt;p&gt;Author: {{article.author.name}}&lt;/p&gt;

&lt;article&gt;{{article.body}}&lt;/article&gt;

{{#if article.comment_count}}
&lt;p&gt;Yahoo! This article has got some comments!&lt;/p&gt;
{{/if}}
Trimming white space When Curlybars processes a template, it displays any verbatim text as is. That's good and works well most of the time. However, sometimes you need to have more control on the blank characters next to an expression. Take the following code for example: Click me!
It renders the following HTML when highlighted is true: Click me!
There's a leading and a trailing space around the word highlight. This of course works fine, but suppose you want to keep the spaces in the template without rendering them. You can use the tilde character (~). Adding a tilde character in your opening or closing curly brackets trims white space from the enclosed text. Example: Click me!
The tilde characters trim the leading and a trailing spaces around the word highlight: Click me!
The tilde character trims any blank character that doesn't have a graphical representation but affects spacing or split lines, such as newlines, tabs, carriage returns, line feeds, simple spaces, or tabs. This means you can take the example to an extreme and express the previous if block on more lines to make it more readable. Example: <a href="..." class="
{{~#if highlighted~}}
highlight
{{~/if~}}
"&gt;Click me!&lt;/a&gt;
This still renders as follows: Click me!
These examples don't make much sense in real life, but the effectiveness of using the tilde character can vary from case to case. Helpers Accessing data, displaying it, and adding some conditional logic can be all you need in some templates. Still, you might like some added functionality. For example, you might want to display a localized string that changes according to the locale of the page requester. Or you might want to truncate a long passage of text. You can get this kind of functionality in templates with helpers. For all the helpers you can use in your templates, see Help Center Templates on developer.zendesk.com. For example, you can use a helper named excerpt in the Article page template to truncate strings. In the article example, suppose you need to show a truncated version of the article title. You can do this by modifying the template as follows: {{excerpt article.title characters=50}}

&lt;p&gt;Author: {{article.author.name}}&lt;/p&gt;

&lt;article&gt;{{article.body}}&lt;/article&gt;
The example above shows that curly brackets are used to invoke a helper. The excerpt helper accepts a parameter that consists of an expression that resolves to a string. The helper has a characters option to specify the number of characters to keep. The characters option isn't mandatory. If you don't specify it, a default value is used. See excerpt in Help Center Templates for further details. The syntax to invoke a helper is {{<helper> [ ...] [<key=value> ...]}}. The only mandatory element is the name of the helper. Parameters and options vary depending on the helper. Now, suppose you want to update the template to display a cheerful message when the author's name is John Venturini. Unfortunately, you can't use an if condition to check if article.author.name is equal to "John Venturini" because if only works on one expression. Comparison operators like == are not available. How to add such a logic then? Fortunately, you can use the is helper. It takes two parameters and tests them for equality. Example: {{excerpt article.title characters=50}}

{{#is article.author.name 'John Venturini'}}
&lt;p&gt;Cool! John Venturini is the author of this article!&lt;/p&gt;
{{/is}}

&lt;article&gt;{{article.body}}&lt;/article&gt;
The snippet above renders the cheerful message if the author is John Venturini. But what if you want to render a different message if it's not him? The good news is that is can also include an else block just like the if-else statement. To restore the old message if the author is not John Venturini, you can add an else block as follows: {{excerpt article.title characters=50}}

{{#is article.author.name 'John Venturini'}}
&lt;p&gt;Cool! John Venturini is the author of this article!&lt;/p&gt;
{{else}}
&lt;p&gt;Author: {{article.author.name}}&lt;/p&gt;
{{/is}}

&lt;article&gt;{{article.body}}&lt;/article&gt;
Changing scope Accessing data is pretty straightforward using dot notation, especially when the path to the information we need is not too long. Example: article.title. In some circumstances, though, you might want to access a property with a longer path. Example: article.author.name. You can use longer paths in templates if you want. For example, you can add the author's name and avator in the example as follows: {{excerpt article.title characters=50}}

&lt;img src="{{article.author.avatar_url}}" alt="Author's avatar" height="42" width="42"&gt;
{{#is article.author.name 'John Venturini'}}
&lt;p&gt;Cool! John Venturini is the author of this article!&lt;/p&gt;
{{else}}
&lt;p&gt;Author: {{article.author.name}}&lt;/p&gt;
{{/is}}

&lt;article&gt;{{article.body}}&lt;/article&gt;
The snippet above works just fine, but the long property paths make the code look a little cluttered. One way around the problem is to use the special with construct. with accepts one parameter that represents the base context to use in the code block associated with it. The syntax is as follows: {{#with <context>}}
...
{{/with}}
You can improve the example as follows: {{excerpt article.title characters=50}}

{{#with article.author}}
&lt;img src="{{avatar_url}}" alt="Author's avatar" height="42" width="42"&gt;
{{#is name 'John Venturini'}}
&lt;p&gt;Cool! John Venturini is the author of this article!&lt;/p&gt;
{{else}}
&lt;p&gt;Author: {{name}}&lt;/p&gt;
{{/is}}
{{/with}}

&lt;article&gt;{{article.body}}&lt;/article&gt;
The article.author parameter eliminates the need to include article.author in any paths in the block. So {{name}} inside the block is equivalent to article.author.name outside the block. You can't use article.author.name in the block because it would be evaluated as article.author.article.author.name. Similarly, you can't access the title of the article in the block with article.title because the article object is accessible only in the root context, which is outside the block. To escape from the context set by with and access the outer context, use the ../ notation in the path. You can render the title of the article inside the with block as follows: {{excerpt article.title characters=50}}

{{#with article.author}}
{{../article.title}}

&lt;img src="{{avatar_url}}" alt="Author's avatar" height="42" width="42"&gt;
{{#is name 'John Venturini'}}
&lt;p&gt;Cool! John Venturini is the author of this article!&lt;/p&gt;
{{else}}
&lt;p&gt;Author: {{name}}&lt;/p&gt;
{{/is}}
{{/with}}

&lt;article&gt;{{article.body}}&lt;/article&gt;
You can use the ../ notation repeatedly in the same path. It'll jump back the same number of contexts. For instance, the following example will still work as expected: {{excerpt article.title characters=50}}

{{#with article}}
{{#with author}}
{{../../article.title}}

...

{{/with}}

&lt;article&gt;{{article.body}}&lt;/article&gt;
You might want to be defensive and render a specific message whenever the author is not specified. You might decide to use an if block to do this, as follows: {{excerpt article.title characters=50}}

{{#if article.author}}
{{#with article.author}}
...
{{/with}}
{{else}}
No author is present for this article!
{{/if}}

&lt;article&gt;{{article.body}}&lt;/article&gt;
Note that in Help Center, article.author is actually never null. We assumed so here only for the sake of the example. The snippet above works just fine, but you can achieve the same result with an else block in the with construct. The else block is executed if the parameter is falsy. You can modify the example as follow: {{excerpt article.title characters=50}}

{{#with article.author}}
...
{{else}}
No author is present for this article!
{{/with}}

&lt;article&gt;{{article.body}}&lt;/article&gt;
Using an else block also makes the code more readable. Passing the root context to a helper Use the this keyword to pass the current root context to a helper. Suppose you have a render_author helper that accepts an article object as a parameter in order to display details about its author. You can use the this keyword as follows: {{excerpt article.title characters=50}}

{{#with article}}
{{render_author this}}
{{/with}}

&lt;article&gt;{{article.body}}&lt;/article&gt;
this will be resolved as article. Accessing items in an array Some help center properties consist of arrays of objects. For example, the attachments property consists of an array of attachments. To access the items in an array, you need to iterate over each one. The each helper does exactly that. Example: {{excerpt article.title characters=50}}

{{#with article.author}}
...
{{/with}}

&lt;article&gt;{{article.body}}&lt;/article&gt;

{{#each attachments}}
&lt;a href="{{url}}" target="_blank"&gt;{{name}}&lt;/a&gt;
&lt;span&gt;({{size}})&lt;/span&gt;
{{/each}}
The snippet above lists all the attachments. Each list item displays data specific to one attachment, such as its url, name, and size. Like with, each changes the context in its block. This means that if you want to access the outer context, you can use the ../ notation. You might want to render a message when an array is empty. You can easily achieve this by using an if block, as follows: ...

{{#if attachments}}
{{#each attachments}}
&lt;a href="{{url}}" target="_blank"&gt;{{name}}&lt;/a&gt;
&lt;span&gt;({{size}})&lt;/span&gt;
{{/each}}
{{else}}
Sorry, no attachments available!
{{/if}}
This works just fine, but you could also use an else block to make the code easier to read: ...

{{#each attachments}}
&lt;a href="{{url}}" target="_blank"&gt;{{name}}&lt;/a&gt;
&lt;span&gt;({{size}})&lt;/span&gt;
{{else}}
Sorry, no attachments available!
{{/each}}
Length Every array has an implicit length property that gives the number of elements in the array. For example, if you want to display the number of attachments, use the length property as follows: ...

There are {{attachments.length}}.

{{#each attachments}}
&lt;a href="{{url}}" target="_blank"&gt;{{name}}&lt;/a&gt;
&lt;span&gt;({{size}})&lt;/span&gt;
{{/each}} Subexpressions Subexpressions allow you to invoke multiple helpers within a single expression, and pass the results of inner helper invocations as arguments to outer helpers. Subexpressions are delimited by parentheses. The following example shows a subexpression in an expression: {{search placeholder=(dc "search_text")}} Subexpressions can be nested: {{search placeholder=(excerpt (dc "search_text"))}} Subexpressions can be used in conditional helpers: {{#if (compare collection.length "==" 0)}}
&lt;div&gt;Empty collection.&lt;/div&gt;
{{else}}
&lt;div&gt;Your collection has {{collection.length}} items&lt;/div&gt;
{{/if}} Subexpressions can be used in array iterator helpers: {{#each (slice (filter user.badges on="category_slug" equals="achievements")
0 4)}}

&lt;section&gt;
&lt;h3&gt;{{name}}&lt;/h3&gt;
&lt;div&gt;{{description}}&lt;/div&gt;
&lt;/section&gt;
{{/each}}

{
"@context": "https://schema.org",
"@type": "TechArticle",
"@id": "https://support.zendesk.com/hc/en-us/articles/4408824571674",
"url": "https://support.zendesk.com/hc/en-us/articles/4408824571674-Using-the-help-center-templating-language",
"headline": "Using the help center templating language",
"description": "You can use the Curlybars templating language to customize help center page templates by inserting dynamic content, applying conditional logic, and manipulating data structures within the HTML layout.",
"articleSection": "Using themes and customizing your help center",
"datePublished": "2021-10-16T03:47:15+00:00",
"dateModified": "2026-01-21T19:43:52+00:00",
"inLanguage": "en-US",
"mainEntityOfPage": {
"@type": "WebPage",
"@id": "https://support.zendesk.com/hc/en-us/articles/4408824571674"
},
"author": {
"@type": "Organization",
"name": "Zendesk",
"@id": "https://www.zendesk.com"
},
"publisher": {
"@type": "Organization",
"name": "Zendesk",
"@id": "https://www.zendesk.com"
},
"isPartOf": {
"@type": "WebSite",
"name": "Zendesk Help",
"@id": "https://support.zendesk.com/hc/"
},
"about": {
"@type": "SoftwareApplication",
"name": "Zendesk",
"@id": "https://www.zendesk.com",
"softwareAddOn": {
"@type": "SoftwareApplication",
"name": "Knowledge",
"@id": "https://support.zendesk.com/hc/en-us/sections/4405298860954"
}
}
}
