Go html/template
When Handlebars is not expressive enough, use Go's
html/template. Used when a directory
contains template.tmpl.
<h1>Invoice {{ .number }}</h1>
{{ range .items }}
<div>{{ .name }} — {{ .price }}</div>
{{ end }}
{{ if eq .status "paid" }}Paid{{ else }}Due{{ end }}
<time>{{ .issuedAt | format_time "%Y-%m-%d" }}</time>
Features
- The full Go template language:
range,if/else,with, variables, pipelines, and comparison functions (eq,lt, …). - Helpers:
format_time,markdown,embed_text,embed_base64— usable positionally or via pipes. - Partials via
{{ template "name" . }}, including Markdown partials. - Context-aware auto-escaping:
html/templateescapes according to HTML/JS/ URL context, which is a strong XSS defense.markdownreturnstemplate.HTMLandembed_textreturns the type matching the file it read (.css→template.CSS,.js→template.JS, anything else →template.HTML), so each lands unescaped in the context it belongs to — do not pass either untrusted data.
Formatting numbers
html/template carries Go's own template
built-ins alongside the
project's helpers — printf, len, index, slice, call, and the
comparison set. They cannot be switched off, and printf is the reason to
choose this engine when the data arrives as plain numbers:
{{/* two decimals: 27.2 -> 27.20 */}}
<td>{{ printf "%.2f" .amount }} EUR</td>
{{/* a percentage, from a rate the data carries as 20 */}}
<td>{{ printf "%.0f%%" .ratePercent }}</td>
It formats; it does not compute. Rendering 0.2 as 20% means
multiplying by 100, and nothing here multiplies — send ratePercent: 20
rather than rate: 0.2. The same goes for every total: line totals,
subtotals, tax and grand totals are computed by whatever builds the data.
printf is Go's fmt, so it has no notion of a locale: it will not group
thousands or place a currency symbol per locale. If you need 1 234 567,89,
format the string in the caller and place it as text.
Choose Go templates when you need real control flow and computed logic in the template itself.