Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.fileloom.io/llms.txt

Use this file to discover all available pages before exploring further.

Fileloom uses Handlebars as its templating engine. This guide covers the syntax you need to create dynamic PDFs.

Basic Output

Output variables using double curly braces:
<h1>Hello, {{name}}!</h1>
<p>Your order #{{orderNumber}} is confirmed.</p>
With data {"name": "John", "orderNumber": "12345"}:
<h1>Hello, John!</h1>
<p>Your order #12345 is confirmed.</p>

Nested Properties

Access nested object properties with dot notation:
<p>{{customer.name}}</p>
<p>{{customer.address.street}}</p>
<p>{{customer.address.city}}, {{customer.address.state}} {{customer.address.zip}}</p>
With data:
{
  "customer": {
    "name": "Acme Corp",
    "address": {
      "street": "123 Main St",
      "city": "San Francisco",
      "state": "CA",
      "zip": "94102"
    }
  }
}

HTML Escaping

By default, Handlebars escapes HTML characters for security:
{{description}}
Input: <script>alert('xss')</script> Output: &lt;script&gt;alert('xss')&lt;/script&gt; To output raw HTML (use carefully):
{{{rawHtml}}}
Only use triple braces {{{ for HTML you trust. Never use it with user-generated content.

Conditionals

Simple If

{{#if isPaid}}
  <span class="badge paid">PAID</span>
{{/if}}

If-Else

{{#if isPaid}}
  <span class="badge paid">PAID</span>
{{else}}
  <span class="badge unpaid">UNPAID</span>
{{/if}}

If-Else-If

{{#if isOverdue}}
  <span class="badge overdue">OVERDUE</span>
{{else if isPending}}
  <span class="badge pending">PENDING</span>
{{else}}
  <span class="badge paid">PAID</span>
{{/if}}

Falsy Values

{{#if}} treats these as false:
  • false
  • undefined
  • null
  • "" (empty string)
  • 0
  • [] (empty array)

Unless (Inverse If)

{{#unless isPaid}}
  <p class="warning">Payment required</p>
{{/unless}}

Loops

Each

Iterate over arrays:
<table>
  {{#each items}}
    <tr>
      <td>{{this.name}}</td>
      <td>{{this.quantity}}</td>
      <td>{{currency this.price "USD"}}</td>
    </tr>
  {{/each}}
</table>
With data:
{
  "items": [
    {"name": "Widget", "quantity": 2, "price": 29.99},
    {"name": "Gadget", "quantity": 1, "price": 49.99}
  ]
}

Loop Variables

Inside {{#each}}, special variables are available:
VariableDescription
thisCurrent item
@indexZero-based index (0, 1, 2…)
@firstTrue if first item
@lastTrue if last item
@keyProperty name (for objects)
{{#each items}}
  <tr class="{{#if @first}}first-row{{/if}} {{#if @last}}last-row{{/if}}">
    <td>{{add @index 1}}.</td>
    <td>{{this.name}}</td>
  </tr>
{{/each}}

Empty Arrays

Handle empty arrays with {{else}}:
{{#each items}}
  <tr><td>{{this.name}}</td></tr>
{{else}}
  <tr><td>No items found</td></tr>
{{/each}}

Iterating Objects

Loop through object properties:
{{#each person}}
  <p>{{@key}}: {{this}}</p>
{{/each}}
With data {"person": {"name": "John", "age": 30}}:
<p>name: John</p>
<p>age: 30</p>

Using Helpers

Helpers transform or format data:
{{! Single argument }}
{{uppercase name}}

{{! Multiple arguments }}
{{currency amount "EUR"}}

{{! With string literals }}
{{formatDate date "MMMM D, YYYY"}}

{{! Nested helpers }}
{{currency (multiply price quantity) "USD"}}

Common Helpers

{{! Text }}
{{uppercase "hello"}}              → HELLO
{{lowercase "HELLO"}}              → hello
{{capitalize "john doe"}}          → John doe
{{titleCase "john doe"}}           → John Doe

{{! Numbers }}
{{currency 1234.5 "USD"}}          → $1,234.50
{{formatNumber 1234567 0}}         → 1,234,567
{{percentage 75 100}}              → 75.0%

{{! Dates }}
{{formatDate date "YYYY-MM-DD"}}   → 2024-12-15
{{formatDate date "MMMM D, YYYY"}} → December 15, 2024
{{now "YYYY"}}                     → 2024

{{! Math }}
{{add 10 5}}                       → 15
{{multiply 10 5}}                  → 50
{{round 3.7}}                      → 4
See Helpers Reference for all 70+ helpers.

Comments

Add comments that won’t appear in output:
{{! This is a comment }}

{{!-- 
  This is a 
  multi-line comment 
--}}

Whitespace Control

Control whitespace with ~:
{{#each items ~}}
  {{this.name}}
{{~/each}}
The ~ removes whitespace on that side of the tag.

Partials (Reusable Snippets)

While Fileloom doesn’t support custom partials, you can achieve reusability with:
  1. CSS classes for consistent styling
  2. Helper functions for data transformation
  3. Template duplication for similar documents

Practical Examples

Invoice Line Items with Totals

<table class="items">
  <thead>
    <tr>
      <th>Description</th>
      <th>Qty</th>
      <th>Price</th>
      <th>Total</th>
    </tr>
  </thead>
  <tbody>
    {{#each items}}
    <tr>
      <td>{{this.description}}</td>
      <td>{{this.quantity}}</td>
      <td>{{currency this.unitPrice "USD"}}</td>
      <td>{{currency (multiply this.quantity this.unitPrice) "USD"}}</td>
    </tr>
    {{/each}}
  </tbody>
  <tfoot>
    <tr>
      <td colspan="3">Subtotal</td>
      <td>{{currency subtotal "USD"}}</td>
    </tr>
    <tr>
      <td colspan="3">Tax ({{percentage taxRate 1 0}})</td>
      <td>{{currency tax "USD"}}</td>
    </tr>
    <tr class="total">
      <td colspan="3">Total</td>
      <td>{{currency total "USD"}}</td>
    </tr>
  </tfoot>
</table>

Conditional Sections

<div class="invoice-header">
  <h1>Invoice #{{invoiceNumber}}</h1>
  
  {{#if isPaid}}
    <div class="stamp paid">
      PAID
      <span class="date">{{formatDate paidDate "MMM D, YYYY"}}</span>
    </div>
  {{else if isOverdue}}
    <div class="stamp overdue">
      OVERDUE
      <span class="days">{{daysBetween dueDate}} days</span>
    </div>
  {{/if}}
</div>

Address Formatting

<address>
  {{customer.name}}<br>
  {{#if customer.company}}{{customer.company}}<br>{{/if}}
  {{customer.address.street}}<br>
  {{#if customer.address.unit}}{{customer.address.unit}}<br>{{/if}}
  {{customer.address.city}}, {{customer.address.state}} {{customer.address.zip}}<br>
  {{#if customer.address.country}}{{customer.address.country}}{{/if}}
</address>