HTX is a simple, composable, and testable Go HTML template extension for the Go html/template package.
- base layouts
- partial includes
- inline string rendering
- template caching
- custom template functions
- glob pattern loading
- easy to use and test
go get github.com/shayanderson/htx
func main() {
e := htx.New(htx.Config{
Base: "layout/base",
Extension: ".html",
Load: []string{"partials/*.html"},
Root: "app/view",
})
var buf bytes.Buffer
err := e.Render(&buf, "index", map[string]any{
"name": "World",
})
if err != nil {
panic(err)
}
fmt.Println(buf.String())
}
All engine configuration:
Base
- base layout template name (without extension), e.g.layout/base
DisableCache
- disable template caching (default:false
)Extension
- template file extension, will be applied to all templates without file extensions (default:.html
)Funcs
- custom template functions (see Template Functions)Load
- additional partial templates to load (supports glob patterns), e.g.partials/*.html
Root
- root directory for templates (default: current working directory)
app/view/layout/base.html
- base layout with header include and content block
<!DOCTYPE html>
<html>
<head>
<title>{{ .title }}</title>
</head>
<body>
{{ include "layout/header" . }}
<!-- content defined in other templates -->
{{ block "content" . }}{{ end }}
</body>
</html>
app/view/layout/header.html
- header partial
<header>header</header>
app/view/partials/banner.html
- banner partial, loaded via config Load
option
<div class="banner">Welcome, {{ .name }}!</div>
app/view/index.html
- main index template
<!-- content block will be injected into base layout -->
{{ define "content" }}
<h1>Hello, {{ .name }}!</h1>
{{ include "banner" . }} {{ end }}
You can render a template from a string instead of a file with the RenderString
method.
tpl := `
{{ define "content" }}
<h1>Hello, {{ .name }}!</h1>
{{ include "banner" . }}
{{ end }}
`
var buf bytes.Buffer
err := e.RenderString(&buf, tpl, map[string]any{
"name": "World",
})
if err != nil {
panic(err)
}
fmt.Println(buf.String())
You can override the engine config options per render call via the Options
struct.
err := e.Render(&buf, "index", data, htx.Options{
// disable base layout for this render
DisableBase: true,
// add custom template functions for this render
Funcs: template.FuncMap{
"myFunc": func() string { return "myFuncVal" },
},
// load additional partials for this render
Load: []string{"other_partials/*.html"},
})
All render options:
DisableBase
- disable base layout for this render (default:false
)DisableCache
- disable template caching for this render (default:false
)Funcs
- additional custom template functions for this render (see Template Functions)Load
- additional partial templates to load for this render (supports glob patterns)
You can add custom template functions via the Funcs
field in the Config
struct or via the Options
struct when rendering.
Default functions:
get
- get a value from the engine store by key, e.g.{{ get "year" }}
- example set store value:
e.Store("year", 2025)
- example set store value:
include
- include another template partial, e.g.{{ include "header" . }}
list
- creates a list- for iteration:
{{ range list 1 2 3 }}{{ . }}{{ end }}
- as a template variable:
{{ template "myTemplate" (list 1 2 3) }}
- for iteration:
map
- creates a map- for use in templates:
{{ $m := map "key1" "val1" "key2" "val2" }}{{ $m.key1 }}
- as a template variable:
{{ template "myTemplate" (map "key1" "val1" "key2" "val2") }}
- can use with
list
as value:{{ template "myTemplate" (map "key1" (list 1 2 3) "key2" "val2") }}
- for use in templates:
You can set up a default engine to use throughout your app.
e := htx.New(htx.Config{
// ...
})
htx.SetDefault(e)
// later in your code
err := htx.Render(&buf, "index", data)
// or access engine directly
htx.Default()
Test templates exist in testdata/
and can be tested with:
make test