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.

Follow these best practices to create templates that are reliable, maintainable, and produce professional results.

HTML Structure

Use Semantic HTML

<!-- Good -->
<header class="invoice-header">
  <h1>Invoice #{{invoiceNumber}}</h1>
</header>
<main class="invoice-body">
  <section class="customer-info">...</section>
  <section class="line-items">...</section>
</main>
<footer class="invoice-footer">...</footer>

<!-- Avoid -->
<div class="div1">
  <div class="div2">Invoice #{{invoiceNumber}}</div>
</div>

Keep Structure Flat

Avoid deeply nested elements that complicate styling:
<!-- Good -->
<div class="card">
  <h2 class="card-title">{{title}}</h2>
  <p class="card-body">{{content}}</p>
</div>

<!-- Avoid -->
<div class="wrapper">
  <div class="container">
    <div class="inner">
      <div class="content">
        <h2>{{title}}</h2>
      </div>
    </div>
  </div>
</div>

CSS Guidelines

Use Classes, Not IDs

Classes are reusable and have consistent specificity:
/* Good */
.invoice-total { font-weight: bold; }
.highlight { background: #ffffcc; }

/* Avoid */
#main-total { font-weight: bold; }

Define a Base Style

Start with consistent defaults:
* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

body {
  font-family: 'Inter', Arial, sans-serif;
  font-size: 12px;
  line-height: 1.5;
  color: #333;
}

h1, h2, h3 {
  margin-bottom: 0.5em;
}

p {
  margin-bottom: 1em;
}

Use CSS Variables

Make theming and updates easier:
:root {
  --color-primary: #2563eb;
  --color-secondary: #64748b;
  --color-success: #22c55e;
  --color-danger: #ef4444;
  --color-border: #e2e8f0;
  --font-main: 'Inter', sans-serif;
  --font-mono: 'JetBrains Mono', monospace;
}

.header {
  background: var(--color-primary);
  color: white;
}

.total {
  color: var(--color-success);
}
Optimize for print output:
/* Avoid page breaks inside elements */
.item-row {
  page-break-inside: avoid;
}

/* Force page break before element */
.new-section {
  page-break-before: always;
}

/* Keep heading with following content */
h2 {
  page-break-after: avoid;
}

Data Handling

Always Handle Missing Data

Use defaults and conditionals:
{{! Use default helper }}
{{default customer.name "Valued Customer"}}

{{! Use conditional }}
{{#if customer.phone}}
  <p>Phone: {{customer.phone}}</p>
{{/if}}

{{! Handle empty arrays }}
{{#each items}}
  <tr>...</tr>
{{else}}
  <tr><td colspan="4">No items</td></tr>
{{/each}}

Validate Data Types

Ensure data is the expected type:
{{! Numbers - use formatNumber to ensure formatting }}
{{formatNumber quantity 0}}

{{! Dates - use formatDate to ensure parsing }}
{{formatDate date "YYYY-MM-DD"}}

{{! Currency - always specify currency code }}
{{currency amount "USD"}}

Test Edge Cases

Test your template with:
  • Empty strings and null values
  • Empty arrays
  • Very long text
  • Large numbers
  • Special characters
  • Missing optional fields

Performance

Optimize Images

<!-- Specify dimensions to prevent layout shifts -->
<img src="{{logoUrl}}" width="200" height="50" alt="Logo">

<!-- Use appropriate formats -->
<!-- PNG for logos with transparency -->
<!-- JPEG for photographs -->
<!-- SVG for icons and simple graphics -->

Minimize External Resources

<!-- Good: Inline critical styles -->
<style>
  .invoice { ... }
</style>

<!-- Avoid: Multiple external stylesheets -->
<link href="https://..." rel="stylesheet">
<link href="https://..." rel="stylesheet">
<link href="https://..." rel="stylesheet">

Keep Templates Focused

Create separate templates for different document types rather than one complex template with many conditionals.

Fonts

Use Web-Safe Fonts or Google Fonts

Fileloom automatically injects common fonts, but for custom fonts:
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap" rel="stylesheet">

Provide Fallbacks

body {
  font-family: 'Custom Font', 'Inter', Arial, sans-serif;
}

Limit Font Weights

Only load weights you need:
<!-- Good: Only needed weights -->
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap" rel="stylesheet">

<!-- Avoid: All weights -->
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@100;200;300;400;500;600;700;800;900&display=swap" rel="stylesheet">

Tables

Use Proper Table Structure

<table class="data-table">
  <thead>
    <tr>
      <th>Description</th>
      <th>Qty</th>
      <th>Price</th>
    </tr>
  </thead>
  <tbody>
    {{#each items}}
    <tr>
      <td>{{this.description}}</td>
      <td>{{this.quantity}}</td>
      <td>{{currency this.price "USD"}}</td>
    </tr>
    {{/each}}
  </tbody>
  <tfoot>
    <tr>
      <td colspan="2">Total</td>
      <td>{{currency total "USD"}}</td>
    </tr>
  </tfoot>
</table>

Style Tables for Print

table {
  width: 100%;
  border-collapse: collapse;
}

th, td {
  padding: 8px 12px;
  text-align: left;
  border-bottom: 1px solid var(--color-border);
}

thead {
  background: #f8fafc;
}

/* Repeat header on each page */
thead {
  display: table-header-group;
}

/* Keep rows together */
tr {
  page-break-inside: avoid;
}

Maintainability

Comment Complex Logic

{{! Calculate line total: quantity × unit price }}
{{currency (multiply this.quantity this.unitPrice) "USD"}}

{{!-- 
  Payment status badge
  - Green for paid
  - Yellow for pending
  - Red for overdue
--}}
{{#if isPaid}}
  <span class="badge badge-success">Paid</span>
{{else if isOverdue}}
  <span class="badge badge-danger">Overdue</span>
{{else}}
  <span class="badge badge-warning">Pending</span>
{{/if}}

Use Consistent Naming

/* BEM-style naming */
.invoice { }
.invoice__header { }
.invoice__body { }
.invoice__footer { }
.invoice__total { }
.invoice__total--highlighted { }

/* Or simple descriptive names */
.invoice-header { }
.invoice-body { }
.customer-info { }
.line-items { }
.payment-terms { }

Document Your Templates

Add a comment block at the top:
{{!--
  Template: Professional Invoice
  Version: 2.1
  Last Updated: 2024-12-15
  
  Required fields:
  - invoiceNumber (string)
  - date (ISO date string)
  - customer (object: name, address, city, state, zip)
  - items (array: description, quantity, unitPrice)
  - subtotal, tax, total (numbers)
  
  Optional fields:
  - customer.company
  - notes
  - paymentTerms
--}}

Checklist

Before publishing a template:
  • Test with real data from your application
  • Verify all variables have default handling
  • Check empty array scenarios
  • Test with long text content
  • Verify page breaks look correct
  • Check on different paper sizes
  • Validate all links and images load
  • Review with fresh eyes or a colleague