Templates
Learn to use Handlebars templates to create dynamic pages.
Handlebars Basics
Section titled “Handlebars Basics”Balzac uses Handlebars templating. Templates use {{variable}} for variables and {{#helper}}...{{/helper}} for helpers.
Variables
Section titled “Variables”Output variable values:
<h1>{{site_name}}</h1><p>{{author}}</p>HTML-escaped by default. Use triple braces for raw HTML:
<div class="content"> {{{content}}}</div>Conditionals
Section titled “Conditionals”{{#if is_published}} <span>Published</span>{{else}} <span>Draft</span>{{/if}}<ul> {{#each tags}} <li>{{this}}</li> {{/each}}</ul>Template Variables
Section titled “Template Variables”Global Variables
Section titled “Global Variables”Variables from your balzac.toml [global] section:
[global]site_name = "My Site"author = "John Doe"Use anywhere:
<h1>{{site_name}}</h1><p>By {{author}}</p>Collection Variables
Section titled “Collection Variables”When rendering collection items:
<h1>{{fm.title}}</h1><p>{{fm.description}}</p><div class="content"> {{{content}}}</div>Partials
Section titled “Partials”Reusable template components.
Creating Partials
Section titled “Creating Partials”Create files in partials/ directory:
partials/header.hbs:
<header> <a href="/">{{site_name}}</a> <nav> <a href="/about.html">About</a> <a href="/contact.html">Contact</a> </nav></header>partials/footer.hbs:
<footer> <p>© 2024 {{site_name}}</p></footer>Using Partials
Section titled “Using Partials”Include partials with {{> partial-name}}:
<!DOCTYPE html><html> <body> {{> header}} <main> <h1>{{title}}</h1> </main> {{> footer}} </body></html>Passing Data to Partials
Section titled “Passing Data to Partials”{{> post-card title=fm.title date=fm.date}}partials/post-card.hbs:
<article> <h2>{{title}}</h2> <time>{{date}}</time></article>Layouts
Section titled “Layouts”Reusable page layouts.
Creating Layouts
Section titled “Creating Layouts”layouts/default.hbs:
<!DOCTYPE html><html lang="en"> <head> <meta charset="UTF-8"> <title>{{title}}</title> <link rel="stylesheet" href="/assets/style.css"> </head> <body> {{> header}} <main> {{{body}}} </main> {{> footer}} </body></html>Using Layouts
Section titled “Using Layouts”You can use partials to implement layouts:
pages/index.hbs:
{{> header}}<main> <h1>Welcome to {{site_name}}</h1></main>{{> footer}}Or create a layout partial with slots:
layouts/main.hbs:
<!DOCTYPE html><html> <body> {{> header}} {{{yield}}} {{> footer}} </body></html>pages/index.hbs:
{{> main}} {{#*inline "yield"}} <h1>Welcome to {{site_name}}</h1> {{/inline}}{{/main}}Built-in Helpers
Section titled “Built-in Helpers”vite_url
Section titled “vite_url”When Vite bundler is enabled, resolve asset URLs:
<script src='{{vite_url "main.js"}}'></script><link rel="stylesheet" href='{{vite_url "style.css"}}'>Requires Vite bundler configuration:
[bundler.vite]enabled = truemanifest_path = "dist/.vite/manifest.json"Custom Helpers
Section titled “Custom Helpers”Create custom helpers by registering them in the renderer. This requires using Balzac as a library rather than the CLI.
See Configuration for more details.
Example: Blog Post Template
Section titled “Example: Blog Post Template”pages/posts/details.hbs:
<!DOCTYPE html><html lang="en"> <head> <meta charset="UTF-8"> <meta name="description" content="{{fm.description}}"> <title>{{fm.title}} - {{site_name}}</title> <link rel="stylesheet" href="/assets/style.css"> </head> <body> {{> header}}
<article class="post"> <header class="post-header"> <h1>{{fm.title}}</h1> <div class="meta"> <time>{{fm.date}}</time> {{#if fm.author}} <span>By {{fm.author}}</span> {{/if}} </div> {{#if fm.tags}} <div class="tags"> {{#each fm.tags}} <span class="tag">{{this}}</span> {{/each}} </div> {{/if}} </header>
<div class="content"> {{{content}}} </div>
<footer class="post-footer"> <a href="/index.html">← Back to posts</a> </footer> </article>
{{> footer}} </body></html>Example: Homepage with Post List
Section titled “Example: Homepage with Post List”pages/index.hbs:
<!DOCTYPE html><html lang="en"> <head> <meta charset="UTF-8"> <title>{{site_name}}</title> <link rel="stylesheet" href="/assets/style.css"> </head> <body> {{> header}}
<main> <section class="hero"> <h1>Welcome to {{site_name}}</h1> <p>{{description}}</p> </section>
<section class="posts"> <h2>Latest Posts</h2> <!-- Manual post listing - or generate with a hook --> <ul> <li> <a href="/posts/hello-world.html">Hello World</a> <span class="date">2024-01-15</span> </li> <li> <a href="/posts/getting-started.html">Getting Started</a> <span class="date">2024-01-10</span> </li> </ul> </section> </main>
{{> footer}} </body></html>Best Practices
Section titled “Best Practices”- Use partials - Reuse common elements (header, footer, navigation)
- Separate concerns - Keep templates focused on presentation
- Escape user input - Use
{{variable}}by default, only use{{{variable}}}for trusted HTML - Use conditionals - Handle missing data gracefully
- Keep templates simple - Complex logic belongs in preprocessing scripts or hooks
- Organize by purpose - Group related partials and layouts