Template Syntax Reference¶
This is a complete reference guide for Templify's template syntax. Use this as a quick lookup when creating templates.
Table of Contents¶
- Placeholders
- Conditionals
- Loops
- Operators
- Format Specifiers
- Loop Variables
- Markdown Formatting
- Line Breaks in Data
Placeholders¶
Placeholders are replaced with data from your JSON file. They're wrapped in double curly braces: {{...}}
Simple Placeholder¶
JSON:
Template:
Output:
Nested Properties (Dot Notation)¶
Access nested data using dots (.):
JSON:
Template:
Array Indexing¶
Access specific array items by index (starting at 0):
JSON:
{
"Colors": ["Red", "Green", "Blue"],
"Users": [
{ "Name": "Alice", "Age": 25 },
{ "Name": "Bob", "Age": 30 }
]
}
Template:
Case Sensitivity¶
JSON keys are case-sensitive. {{Name}} and {{name}} are different. Always match the exact case used in your JSON data.
Placeholder Name Rules¶
- No spaces inside the braces:
{{Name}}works,{{ Name }}is left unchanged. - Names and keys may contain letters, digits and underscores (
_). Dots separate levels, square brackets index arrays or dictionaries ({{Items[0]}},{{Settings[Theme]}}). - Keys with spaces, hyphens or other special characters (
"first-name","My Key") cannot be used in placeholders, not even in brackets. Rename them in your data. {{.}}or{{this}}refers to the current item inside a loop.
Conditionals¶
Conditionals let you show or hide content based on data values.
Block markers go in their own paragraphs. When
{{#if}},{{#elseif}},{{#else}}and{{/if}}are in separate paragraphs, each marker paragraph is removed completely, including any other text in it. When all markers of a conditional are in one paragraph, only that part of the paragraph changes (an inline conditional):Dear {{#if IsVip}}valued {{/if}}customer.
Basic Conditional¶
JSON:
Template:
Conditional with Else¶
JSON:
Template:
Conditional with ElseIf¶
Use {{#elseif}} for multiple conditions:
{{#if Condition1}}
Content for condition 1
{{#elseif Condition2}}
Content for condition 2
{{#elseif Condition3}}
Content for condition 3
{{#else}}
Default content
{{/if}}
JSON:
Template:
{{#if Score >= 90}}
Grade: A
{{#elseif Score >= 80}}
Grade: B
{{#elseif Score >= 70}}
Grade: C
{{#else}}
Grade: F
{{/if}}
Output:
Note: The {{#else}} branch must always be last.
Conditional with Comparisons¶
Template:
{{#if Age >= 18}}
You are an adult.
{{/if}}
{{#if Score > 90}}
Excellent!
{{#else}}
Keep trying!
{{/if}}
Multiple Conditions¶
Use and or or to combine conditions:
{{#if Condition1 and Condition2}}
Both are true
{{/if}}
{{#if Condition1 or Condition2}}
At least one is true
{{/if}}
JSON:
Template:
{{#if Age >= 18 and HasLicense}}
You can rent a car.
{{/if}}
{{#if Country = "USA" or Country = "Canada"}}
North American customer
{{/if}}
Negation¶
Use not to negate a condition:
{{#if not IsExpired}}
Subscription is active
{{/if}}
{{#if not (Age < 18)}}
You are an adult
{{/if}}
Loops¶
Loops repeat content for each item in an array.
Basic Loop¶
JSON:
Template:
Output:
Nested Loops¶
You can nest loops within each other:
JSON:
{
"Departments": [
{
"Name": "Sales",
"Employees": [
{ "Name": "Alice" },
{ "Name": "Bob" }
]
},
{
"Name": "Engineering",
"Employees": [
{ "Name": "Charlie" },
{ "Name": "Diana" }
]
}
]
}
Template:
{{#foreach Departments}}
Department: {{Name}}
{{#foreach Employees}}
- {{Name}}
{{/foreach}}
{{/foreach}}
Loop Markers Need Their Own Paragraphs¶
A loop repeats whole paragraphs (or table rows). Put {{#foreach}} and {{/foreach}} in their own paragraphs, above and below the content. The marker paragraphs are removed, including any other text in them. A loop whose markers are both in one paragraph ({{#foreach Tags}}{{.}}, {{/foreach}}) does not produce any output; to show a list on one line, prepare the joined text in your data (e.g. "TagList": "red, green, blue").
Loops in Tables¶
Loops can repeat table rows. Put {{#foreach}} and {{/foreach}} in their own rows, above and below the row(s) to repeat:
Template (in Word table):
| Product | Price |
|---|---|
| {{#foreach Items}} | |
| {{Name}} | ${{Price}} |
| {{/foreach}} |
The rows between the marker rows are repeated for each item; the marker rows themselves are removed.
Note: The loop markers must not share a row with the content to repeat. Putting
{{#foreach}}in the first cell and{{/foreach}}in the last cell of the same row is an error (processing fails). A loop whose{{#foreach}}and{{/foreach}}are both inside one cell (in separate paragraphs) repeats paragraphs inside that cell instead.
Conditional Table Rows¶
Table rows can be shown or hidden with {{#if}} / {{#elseif}} / {{#else}} / {{/if}} markers in their own rows:
| Item | Amount |
|---|---|
| Subtotal | {{Subtotal}} |
| {{#if HasDiscount}} | |
| Discount | {{Discount}} |
| {{/if}} | |
| Total | {{Total}} |
Marker rows are removed; the rows of the matching branch are kept, all other branch rows are removed. Conditional rows also work inside table row loops (evaluated per item). If every row of a table is removed, the table is removed as well.
Operators¶
Comparison Operators¶
| Operator | Meaning | Example |
|---|---|---|
= or == |
Equal to | {{#if Status = "Active"}} |
!= |
Not equal to | {{#if Status != "Pending"}} |
> |
Greater than | {{#if Age > 18}} |
< |
Less than | {{#if Price < 100}} |
>= |
Greater than or equal | {{#if Score >= 90}} |
<= |
Less than or equal | {{#if Stock <= 10}} |
Logical Operators¶
| Operator | Meaning | Example |
|---|---|---|
and |
Both conditions true | {{#if Age >= 18 and HasLicense}} |
or |
At least one true | {{#if IsVIP or IsPremium}} |
not |
Negates condition | {{#if not IsExpired}} |
Membership, String, and Existence Operators¶
| Operator | Meaning | Example |
|---|---|---|
in |
Value is in a collection, list literal, or comma-separated string | {{#if Role in Roles}}, {{#if Role in ("Admin", "Editor")}} |
contains |
Substring check (case-sensitive); on a list: membership | {{#if Description contains "urgent"}}, {{#if Tags contains "urgent"}} |
startswith |
Prefix check (case-sensitive; always false on a list) | {{#if Code startswith "US-"}} |
endswith |
Suffix check (case-sensitive; always false on a list) | {{#if FileName endswith ".pdf"}} |
exists |
Variable is present, even if null | {{#if Notes exists}} |
is empty |
Missing, null, blank, or an empty collection | {{#if Notes is empty}} |
is not empty |
Has a value | {{#if Notes is not empty}} |
Negate in with not: {{#if not Role in Roles}}.
Word operators (and, or, not, in, contains, ...) are case-insensitive (AND works too). &&, ||, ===, <> and eq/ne/gt/... are not operators: a condition that uses them cannot be parsed, is treated as false and produces an ExpressionFailed warning.
Operator Precedence¶
From loosest to tightest binding:
| Level | Operators |
|---|---|
| 1 (loosest) | or |
| 2 | and |
| 3 | not |
| 4 | Comparisons (=, ==, !=, >, <, >=, <=), in, contains, startswith, endswith |
| 5 (tightest) | exists, is empty, is not empty (written after the value) |
Parentheses () group explicitly and always win.
andbinds tighter thanor:A or B and CmeansA or (B and C).notbinds looser than comparisons:not Status = "Active"meansnot (Status = "Active"), andnot Role in Rolesmeansnot (Role in Roles).notbinds tighter thanand/or:not A and Bmeans(not A) and B.
Example:
Format Specifiers¶
Format specifiers control how values are displayed. Add them after a colon (:) in the placeholder.
Basic Syntax¶
Common Formats¶
| Format | Description | Example Input | Example Output |
|---|---|---|---|
:uppercase |
Convert to UPPERCASE | "hello" | HELLO |
:lowercase |
Convert to lowercase | "HELLO" | hello |
:yesno |
true/false → Yes/No | true | Yes |
:raw |
Insert text without markdown | "my_file.docx" | my_file.docx |
:checkbox |
true/false → ☑/☐ | false | ☐ |
:number:N2 |
Format number with 2 decimals | 1234.5 | 1,234.50 |
:currency |
Format as currency (en-US culture) | 1234.5 | $1,234.50 |
:date:yyyy-MM-dd |
Format date | (date value) | 2024-01-15 |
Examples¶
JSON:
{
"CustomerName": "alice johnson",
"IsActive": true,
"HasDiscount": false,
"Price": 1234.567,
"OrderDate": "2024-01-15"
}
Template:
Name: {{CustomerName:uppercase}}
Status: {{IsActive:yesno}}
Discount: {{HasDiscount:checkbox}}
Price: {{Price:currency}}
Date: {{OrderDate:date:MMMM d, yyyy}}
Output (en-US culture):
Each specifier applies to one kind of value (text, boolean, number or date); on other values it is ignored. Numbers stored as text ("Price": "1234.5") are not formatted by :currency or :number.
For more format specifier details, see Format Specifiers Guide.
Loop Variables¶
Special variables available inside loops (only there: outside a loop, {{@count}} is not replaced; in nested loops they refer to the innermost loop):
{{@index}}¶
The current loop iteration index (starts at 0):
Template:
Output:
{{@number}}¶
The current item number (starts at 1, i.e. @index + 1; since 1.8.0):
Template:
Output:
{{@first}}¶
True if this is the first iteration:
Template:
{{@last}}¶
True if this is the last iteration:
Template:
Output (one paragraph per item):
{{@count}}¶
Total number of items in the loop:
Template:
Output:
Markdown Formatting¶
Apply formatting to text using markdown syntax in your JSON data:
Bold¶
Or use underscores:
Italic¶
Or use underscores:
Strikethrough¶
Bold + Italic¶
Combining with Template Formatting¶
The markdown formatting is merged with the template's formatting. If your template has red text, and you add **bold** in the data, the output will be red bold text.
Turning Markdown Off¶
Values such as my_report_final.docx or 2*3*4 contain markdown characters. Use {{FileName:raw}} to insert a value literally; developers can switch markdown off for all placeholders with the EnableMarkdown = false option.
Line Breaks in Data¶
Newline characters in your JSON data are automatically converted to line breaks in Word:
Supported formats:
- \n - Unix/Linux/macOS
- \r\n - Windows
- \r - Legacy Mac
Combining with Markdown¶
Line breaks work together with markdown formatting:
Output will have three lines, each with bold text for "Step X:".
Special Characters¶
Literal Curly Braces¶
To include literal {{ or }} in your document without creating a placeholder, there's currently no escape mechanism. Best practice: avoid using {{ in your document text unless it's a placeholder.
Whitespace¶
Templify preserves the whitespace of your content paragraphs:
The marker paragraphs are removed; the content paragraph keeps its indentation.
Quick Syntax Summary¶
| Feature | Syntax | Example |
|---|---|---|
| Placeholder | {{Name}} |
{{CustomerName}} |
| Nested | {{Parent.Child}} |
{{Customer.Address.City}} |
| Array | {{Array[0]}} |
{{Colors[0]}} |
| If | {{#if ...}}...{{/if}} |
{{#if IsActive}}...{{/if}} |
| If/Else | {{#if ...}}...{{#else}}...{{/if}} |
See above |
| If/ElseIf | {{#if ...}}...{{#elseif ...}}...{{/if}} |
See above |
| Loop | {{#foreach ...}}...{{/foreach}} |
{{#foreach Items}}...{{/foreach}} |
| Format | {{Name:format}} |
{{Price:currency}} |
| Loop Index | {{@index}} |
{{@index}} |
| Loop Number | {{@number}} |
{{@number}}. |
| Loop First | {{@first}} |
{{#if @first}}...{{/if}} |
| Loop Last | {{@last}} |
{{#if @last}}...{{/if}} |
| Loop Count | {{@count}} |
{{@count}} |
| Current item | {{.}} or {{this}} |
{{#foreach Tags}}…{{.}}…{{/foreach}} |
| Inline expression | {{(expression)}} |
{{(Age >= 18):yesno}} |
Common Patterns¶
Numbered List¶
List With Separators¶
Each item is its own paragraph. For a list on a single line, provide the joined text in your data.
Conditional with Multiple Checks¶
Nested Conditionals¶
{{#if IsLoggedIn}}
{{#if IsPremium}}
Premium content
{{#else}}
Regular content
{{/if}}
{{#else}}
Please log in
{{/if}}
Table with Conditional Rows¶
| Product | Price | Status |
|---|---|---|
| {{#foreach Products}} | ||
| {{#if InStock}} | ||
| {{Name}} | {{Price}} | Available |
| {{#else}} | ||
| {{Name}} | {{Price}} | Out of Stock |
| {{/if}} | ||
| {{/foreach}} |
For a single differing cell, an inline conditional inside the cell is simpler:
| {{Name}} | {{Price}} | {{#if InStock}}Available{{#else}}Out of Stock{{/if}} |
Best Practices¶
- Match case exactly -
{{Name}}must match"Name"in JSON - Test with simple data first - Start with basic JSON and gradually add complexity
- Use meaningful names -
{{CustomerFirstName}}is better than{{N1}} - Validate JSON - Use jsonlint.com to check JSON syntax
- Comment your templates - Add notes in Word comments about complex logic (comments are not processed, so placeholders in them stay as they are)
- Keep conditionals simple - Break complex logic into multiple simpler conditionals
Next Steps¶
- Placeholders Guide - Deep dive into placeholder usage
- Conditionals Guide - Detailed conditional examples
- Loops Guide - Advanced loop techniques
- Format Specifiers - Complete formatting reference
- Examples Gallery - Real-world template examples
Quick Troubleshooting¶
| Problem | Solution |
|---|---|
| Placeholder not replaced | Check that JSON key matches exactly (case-sensitive) and there are no spaces inside the braces |
| Conditional not working | Verify operator syntax and value types |
| Loop not repeating | Ensure JSON has an array for the loop variable and the markers are in their own paragraphs |
| Formatting not applied | Check format specifier syntax: {{Value:format}} |
| Syntax error | Validate JSON at jsonlint.com |
| Missing data | Check for typos in placeholder names |
For more help, see Best Practices or FAQ.