Documentation / Template filters

Template filters

Format text, prices, dates, and collections directly in your Go templates. Learn the calling conventions first, then use the reference below to find every registered filter.

Available in every Go template

HyperChi copies filters.FuncMap() when you create an application. Templates loaded with app.LoadTemplates can call these functions immediately. They are Go template functions, not a separate expression language. The external templ and Jet integrations do not inherit this function map.

app := hyperchi.New()
helpers.Must(app.LoadTemplates("templates/*.tmpl"))

app.Get("/product", func(c *hyperchi.Context) error {
    return c.View("product.tmpl", hyperchi.H{
        "name": "  field notebook  ",
        "price": 24.5,
        "published": "2026-10-05T12:00:00Z",
    })
})
<h1>{{ .name | trim | title }}</h1>
<p>{{ currency .price "$" }}</p>
<time>{{ .published | dateFormat "Jan 2, 2006" }}</time>

The page displays “Field Notebook”, “$24.50”, and “Oct 5, 2026”. The handler uses only the core hyperchi package. c.View hands the values to the template unchanged, so a time.Time works as well as an RFC 3339 string.

Argument order matters

A Go pipeline places its result in the last argument. Unary functions work naturally in a chain. Most multi-argument HyperChi filters take the value first, so use a direct call or parentheses.

{{ .name | trim | upper }}           <!-- unary chain -->
{{ truncate .name 20 }}             <!-- value first -->
{{ currency .price "€" }}
{{ default .nickname "Anonymous" }}
{{ join (sort .tags) ", " }}
{{ .published | dateFormat "2006-01-02" }} <!-- format first -->

{{ .name | truncate 20 }} is not equivalent to {{ truncate .name 20 }}. It sends 20 as the first argument. Likewise, default takes the value before the fallback. dateFormat intentionally takes the format first and supports the pipeline shown above.

Recipes with live output

These outputs are rendered by this page using the installed filters. Change the literals in your own templates to adapt them.

Clean a label

{{ "  field notebook  " | trim | title }}
ResultField Notebook

Shorten text

{{ truncate "A notebook for every journey" 18 }}
ResultA notebook for ...

Format a price

{{ currency 1234.5 "$" }}
Result$1,234.50

Display a proportion

{{ percent 0.125 1 }}
Result12.5%

Human-readable storage

{{ bytes 1536 }}
Result1.50 KB

Format an ISO date

{{ "2026-10-05T12:00:00Z" | dateFormat "Jan 2, 2006" }}
ResultOct 5, 2026

Use a fallback

{{ default "" "Anonymous" }}
ResultAnonymous

Sort a collection

{{ range sort (list "htmx" "go" "html") }}{{ . }} {{ end }}
Resultgo html htmx

Read nested JSON

{{ jsonGet (fromJSON `{"user":{"name":"Morgan"}}`) "user.name" }}
ResultMorgan

Count items

{{ len (list "Go" "HTML" "HTMX") }}
Result3

Work with collections

sortBy, filter, and pluck accept a collection followed by a field name. Use map keys for maps such as hyperchi.H. For structs, use the exported Go field name. Sorting uses string representations, including in sortBy; sort numeric values in Go when numeric order matters. Keep database queries and business decisions in the handler.

{{ $active := filter .products "active" true }}
{{ range take (sortBy $active "name") 3 }}
  <article>
    <h3>{{ .name }}</h3>
    <p>{{ currency .price }}</p>
  </article>
{{ else }}
  <p>No matching products.</p>
{{ end }}

contains is a substring test for strings and a membership test for slices and arrays (by the rules of eq, so 2 matches 2.0). join expects []string, while many collection transforms return []any. Render those results with range instead of passing them to join.

HTML, JSON, and htmx

Go’s html/template escapes ordinary values for their HTML context. Render visitor text directly; adding escape can double-escape it. nl2br escapes its text before inserting line breaks.

<p>{{ .message }}</p>
<div>{{ nl2br .message }}</div>
<div data-settings="{{ toJSON .settings }}">Settings</div>
<button {{ hxGet "/demo/echo" }} {{ hxTarget "#result" }} {{ hxSwap "innerHTML" }}>
  Load a fragment
</button>
<div id="result" aria-live="polite"></div>

Load htmx separately to activate these attributes. Attribute helpers generate individual attributes: place them side by side, not in a pipeline. Keep attribute names, event expressions, and destinations application-controlled.

safe, unescape, css, and js mark content as trusted; they do not sanitize it. stripTags is a regular-expression transform that also returns trusted HTML, not a security boundary. Only use trusted-content helpers after an appropriate sanitization or application-owned-content boundary.

htmxButton and htmxForm return complete elements, not attributes. They take typed filters.HTMXButtonOptions and filters.HTMXFormOptions, not a dict. Pass the typed options in the handler data, or use literal elements with individual helpers, as above.

Register a custom filter

Register filters during startup, before loading templates and before serving traffic. Use a distinctive name so you do not accidentally replace a built-in function.

app.RegisterFilter("excerpt", func(limit int, text string) string {
    if limit < 0 {
        limit = 0
    }
    runes := []rune(text)
    if len(runes) > limit {
        return string(runes[:limit]) + "…"
    }
    return text
})
helpers.Must(app.LoadTemplates("templates/*.tmpl"))
{{ .description | excerpt 80 }}

This custom function deliberately puts text last for pipeline use. Register several functions with app.RegisterFilters(template.FuncMap{...}). To use the built-ins outside HyperChi, call template.New("page").Funcs(filters.FuncMap()).Parse(source). Package-level filters.Register affects future snapshots; it does not update applications that already copied their function maps.

Types and failure behavior

Functions returning (value, error), such as fromJSON and dateAdd, stop template execution on a non-nil error. Other helpers return fallback values: an unparseable date produces an empty string, while an unconvertible currency value is printed unchanged. Validate input in the handler rather than treating formatting as validation.

default treats false, numeric zero, and empty collections as empty, as well as empty strings and nil. Use coalesce when only nil should trigger a fallback. Validate sizes and indexes before passing visitor-controlled numbers to collection or truncation helpers.

Complete registered reference

Signatures below come from the running filter registry. Arguments appear in call order; ... means variadic arguments and interface {} means any. Expand a category to inspect every function. Functions requiring typed options or callbacks are generally easier to use from Go with direct template execution.

Strings 31 functions
br2nl
func(string) string
camelCase
func(string) string
capitalize
func(string) string
dedent
func(string) string
hasPrefix
func(string, string) bool
hasSuffix
func(string, string) bool
indent
func(string, int, ...string) string
join
func([]string, string) string
kebabCase
func(string) string
lower
func(string) string
nl2br
func(string) template.HTML
pascalCase
func(string) string
pluralize
func(string, ...int) string
quote
func(string) string
repeat
func(string, int) string
replace
func(string, string, string, int) string
replaceAll
func(string, string, string) string
singularize
func(string) string
slug
func(string) string
snakeCase
func(string) string
split
func(string, string) []string
stripTags
func(string) template.HTML
title
func(string) string
trim
func(string) string
trimPrefix
func(string, string) string
trimSuffix
func(string, string) string
truncate
func(string, int, ...string) string
truncateWords
func(string, int, ...string) string
unquote
func(string) string
upper
func(string) string
wordWrap
func(string, int) string
HTML 27 functions
addClass
func(string, string) string
ariaAttrs
func(map[string]interface {}) (template.HTMLAttr, error)
attr
func(string, string) (template.HTMLAttr, error)
checkbox
func(string, interface {}, bool, ...template.HTMLAttr) template.HTML
classNames
func(...interface {}) string
css
func(string) template.CSS
dataAttrs
func(map[string]interface {}) (template.HTMLAttr, error)
escape
func(string) string
formField
func(string, string, interface {}, ...template.HTMLAttr) template.HTML
img
func(string, string, ...template.HTMLAttr) template.HTML
inputAttrs
func(filters.InputOptions) (template.HTMLAttr, error)
js
func(string) template.JS
mailto
func(string, ...string) template.HTML
meta
func(string, string) template.HTML
radio
func(string, interface {}, bool, ...template.HTMLAttr) template.HTML
removeClass
func(string, string) string
safe
func(string) template.HTML
script
func(string, ...template.HTMLAttr) template.HTML
select
func(string, []filters.SelectOption, ...template.HTMLAttr) template.HTML
style
func(string, ...template.HTMLAttr) template.HTML
tel
func(string, ...string) template.HTML
textarea
func(string, interface {}, int, int, ...template.HTMLAttr) template.HTML
toggleClass
func(string, string) string
unescape
func(string) template.HTML
url
func(string) string
urlquery
func(string) string
JSON 12 functions
compactJSON
func(string) (string, error)
fromJSON
func(string) (interface {}, error)
jsonArray
func(...interface {}) []interface {}
jsonAttr
func(string, interface {}) (template.HTMLAttr, error)
jsonEscape
func(string) string
jsonGet
func(interface {}, string) interface {}
jsonLD
func(interface {}) template.HTML
jsonMerge
func(interface {}, interface {}) interface {}
jsonObject
func(...interface {}) map[string]interface {}
jsonSet
func(interface {}, string, interface {}) interface {}
prettyJSON
func(interface {}) (string, error)
toJSON
func(interface {}) (string, error)
Dates and times 26 functions
date
func(interface {}, ...string) string
dateAdd
func(interface {}, int, string) (time.Time, error)
dateCompare
func(interface {}, interface {}) (int, error)
dateDiff
func(interface {}, interface {}, string) (int64, error)
dateFormat
func(string, interface {}) string
dateSub
func(interface {}, int, string) (time.Time, error)
day
func(interface {}) int
durationSeconds
func(time.Duration) float64
fromUnix
func(int64) time.Time
hour
func(interface {}) int
humanDuration
func(interface {}) string
iso8601
func(interface {}) string
minute
func(interface {}) int
month
func(interface {}) string
now
func() time.Time
rfc3339
func(interface {}) string
second
func(interface {}) int
timeAgo
func(interface {}) string
timeFrom
func(interface {}) string
timezone
func(interface {}, string) (time.Time, error)
today
func() time.Time
tomorrow
func() time.Time
unix
func(interface {}) int64
weekday
func(interface {}) string
year
func(interface {}) int
yesterday
func() time.Time
Numbers 25 functions
abs
func(interface {}) float64
add
func(interface {}, interface {}) float64
avg
func(...interface {}) float64
bytes
func(interface {}) string
ceil
func(interface {}) float64
commas
func(string) string
currency
func(interface {}, ...string) string
decimal
func(interface {}, int) string
div
func(interface {}, interface {}) float64
floor
func(interface {}) float64
humanize
func(interface {}) string
max
func(...interface {}) float64
min
func(...interface {}) float64
mod
func(interface {}, interface {}) float64
mul
func(interface {}, interface {}) float64
number
func(interface {}, ...int) string
ordinal
func(interface {}) string
padNumber
func(interface {}, int, ...string) string
percent
func(interface {}, ...int) string
pow
func(interface {}, interface {}) float64
roman
func(interface {}) string
round
func(interface {}, ...int) float64
sqrt
func(interface {}) float64
sub
func(interface {}, interface {}) float64
sum
func(...interface {}) float64
Collections 28 functions
chunk
func(interface {}, int) [][]interface {}
contains
func(interface {}, interface {}) bool
filter
func(interface {}, string, interface {}) []interface {}
find
func(interface {}, string, interface {}) interface {}
findIndex
func(interface {}, string, interface {}) int
first
func(interface {}) interface {}
flatten
func(interface {}) []interface {}
group
func(interface {}, string) map[string][]interface {}
index
func(interface {}, int) interface {}
keys
func(interface {}) []string
last
func(interface {}) interface {}
len
func(interface {}) int
map
func(interface {}, string) []interface {}
merge
func(...interface {}) map[string]interface {}
pairs
func(interface {}) [][]interface {}
pluck
func(interface {}, string) []interface {}
random
func(interface {}) interface {}
reduce
func(interface {}, func(interface {}, interface {}) interface {}, interface {}) interface {}
reverse
func(interface {}) []interface {}
shuffle
func(interface {}) []interface {}
skip
func(interface {}, int) []interface {}
slice
func(interface {}, int, ...int) []interface {}
sort
func(interface {}) []interface {}
sortBy
func(interface {}, string) []interface {}
take
func(interface {}, int) []interface {}
unique
func(interface {}) []interface {}
values
func(interface {}) []interface {}
zip
func(...interface {}) [][]interface {}
HTMX 39 functions
htmxAttrs
func(filters.HTMXAttrs) (template.HTMLAttr, error)
htmxButton
func(filters.HTMXButtonOptions) (template.HTML, error)
htmxForm
func(filters.HTMXFormOptions) (template.HTML, error)
htmxModal
func(string, template.HTML) template.HTML
htmxSpinner
func(string) template.HTML
htmxToast
func(string, string) template.HTML
hxAction
func(string) template.HTMLAttr
hxBoost
func(bool) template.HTMLAttr
hxConfig
func(map[string]interface {}) template.HTMLAttr
hxConfirm
func(string) template.HTMLAttr
hxDelete
func(string) template.HTMLAttr
hxDisabledElt
func(string) template.HTMLAttr
hxEncoding
func(string) template.HTMLAttr
hxGet
func(string) template.HTMLAttr
hxHeaders
func(map[string]string) template.HTMLAttr
hxIgnore
func() template.HTMLAttr
hxInclude
func(string) template.HTMLAttr
hxIndicator
func(string) template.HTMLAttr
hxMethod
func(string) template.HTMLAttr
hxOn
func(string, string) (template.HTMLAttr, error)
hxOptimistic
func(string) template.HTMLAttr
hxPatch
func(string) template.HTMLAttr
hxPost
func(string) template.HTMLAttr
hxPreload
func(string) template.HTMLAttr
hxPreserve
func(interface {}) template.HTMLAttr
hxPushURL
func(string) template.HTMLAttr
hxPut
func(string) template.HTMLAttr
hxReplaceURL
func(interface {}) template.HTMLAttr
hxSelect
func(string) template.HTMLAttr
hxSelectOOB
func(string) template.HTMLAttr
hxStatus
func(string, string) (template.HTMLAttr, error)
hxSwap
func(string) template.HTMLAttr
hxSwapOOB
func(string) template.HTMLAttr
hxSync
func(string) template.HTMLAttr
hxTarget
func(string) template.HTMLAttr
hxTrigger
func(string) template.HTMLAttr
hxValidate
func(bool) template.HTMLAttr
hxVals
func(map[string]interface {}) template.HTMLAttr
Utilities 37 functions
and
func(...interface {}) bool
base64Decode
func(string) (string, error)
base64Encode
func(string) string
coalesce
func(...interface {}) interface {}
default
func(interface {}, interface {}) interface {}
dict
func(...interface {}) map[string]interface {}
empty
func(interface {}) bool
env
func(string, ...string) string
eq
func(interface {}, ...interface {}) bool
fallback
func(...interface {}) interface {}
ge
func(interface {}, interface {}) bool
gt
func(interface {}, interface {}) bool
isNil
func(interface {}) bool
kindOf
func(interface {}) string
le
func(interface {}, interface {}) bool
list
func(...interface {}) []interface {}
lt
func(interface {}, interface {}) bool
ne
func(interface {}, interface {}) bool
not
func(interface {}) bool
notEmpty
func(interface {}) bool
notNil
func(interface {}) bool
or
func(...interface {}) bool
pathBase
func(string) string
pathDir
func(string) string
pathExt
func(string) string
pathJoin
func(...string) string
print
func(...interface {}) string
printf
func(string, ...interface {}) string
println
func(...interface {}) string
regexMatch
func(string, string) (bool, error)
regexReplace
func(string, string, string) (string, error)
regexSplit
func(string, string) ([]string, error)
ternary
func(bool, interface {}, interface {}) interface {}
typeOf
func(interface {}) string
urlDecode
func(string) (string, error)
urlEncode
func(string) string
uuid
func() (string, error)

Keep exploring

Read Templates for composition, Passing data for view models, or the filter implementations and tests for detailed edge behavior. Formatting helpers do not automatically transfer to templ or Jet; those renderers own their data and helper APIs.