text/template generates text output by executing a template written in a small, data-driven action language against a Go value.
Every action sits between {{ and }}. The simplest one, {{.}}, just prints the current data value.
const tmpl = "Hello, {{.}}!"
t := template.Must(template.New("greet").Parse(tmpl))
t.Execute(os.Stdout, "Gopher")Examples
New creates an empty template, Parse fills in its body, and Execute runs it against a data value, writing the result to any io.Writer.
type Item struct {
Name string
Price float64
}
const tmpl = "{{.Name}} costs ${{printf \"%.2f\" .Price}}"
t := template.Must(template.New("item").Parse(tmpl))
t.Execute(os.Stdout, Item{"Widget", 3.5})Widget costs $3.50range walks a slice, setting . to each element in turn. if and with both branch on a pipeline's truthiness, but with also rebinds . inside the block.
const tmpl = "{{range .}}{{if gt . 5}}{{.}} is big\n{{else}}{{.}} is small\n{{end}}{{end}}"
t := template.Must(template.New("nums").Parse(tmpl))
t.Execute(os.Stdout, []int{2, 8, 4})2 is small
8 is big
4 is smallFuncs registers a function usable inside {{ }}. The | operator pipes a value into it, the same shape as a Unix pipeline.
funcs := template.FuncMap{
"upper": strings.ToUpper,
}
const tmpl = "{{.Name | upper}}: {{len .Name}} letters"
t := template.Must(template.New("word").Funcs(funcs).Parse(tmpl))
t.Execute(os.Stdout, struct{ Name string }{"gopher"})GOPHER: 6 lettersdefine declares a named template without rendering it. template invokes one by name, so a layout can call out to a body defined in a separate parse.
const layout = "{{define \"layout\"}}<{{template \"body\" .}}>{{end}}"
const body = "{{define \"body\"}}Hello, {{.}}{{end}}"
t := template.Must(template.New("layout").Parse(layout))
t = template.Must(t.Parse(body))
t.ExecuteTemplate(os.Stdout, "layout", "Gopher")<Hello, Gopher>Constructing & parsing
| Function | Description |
|---|---|
New(name string) *Template template.New("item") | Creates a new, undefined template with the given name |
Must(t *Template, err error) *Template template.Must(template.New("t").Parse(s)) | Wraps a Parse call, panicking if it returned an error |
(*Template) Parse(text string) (*Template, error) t.Parse(tmpl) | Parses text as the template body |
ParseFiles(filenames ...string) (*Template, error) template.ParseFiles("layout.tmpl") | Parses the named files into a new template |
ParseGlob(pattern string) (*Template, error) template.ParseGlob("templates/*.tmpl") | Parses every file matching pattern into a new template |
ParseFS(fsys fs.FS, patterns ...string) (*Template, error) template.ParseFS(embedFS, "templates/*.tmpl") | Like ParseGlob, reading from an fs.FS instead of the OS filesystem |
Executing
| Function | Description |
|---|---|
(*Template) Execute(wr io.Writer, data any) error t.Execute(os.Stdout, data) | Applies the template to data, writing the result to wr |
(*Template) ExecuteTemplate(wr io.Writer, name string, data any) error t.ExecuteTemplate(w, "layout", data) | Like Execute, but runs the named associated template instead of t itself |
(*Template) Funcs(funcMap FuncMap) *Template t.Funcs(template.FuncMap{"upper": strings.ToUpper}) | Registers custom functions callable from the template body |
FuncMap map[string]any template.FuncMap{"add": add} | The map type Funcs accepts, keyed by the name used inside the action |
Template actions
| Function | Description |
|---|---|
{{.}} {{.}} | The current data value |
{{.Field}} / {{.Method}} {{.Name}} | A field or zero-argument method of the current data value |
{{if pipeline}}...{{else}}...{{end}} {{if .Active}}yes{{end}} | Renders the block only if pipeline's result is truthy |
{{range pipeline}}...{{end}} {{range .Items}}{{.}}{{end}} | Repeats the block once per element, setting . to each in turn |
{{with pipeline}}...{{end}} {{with .User}}{{.Name}}{{end}} | Sets . to pipeline's result inside the block, skipping it entirely if the value is empty |
{{define "name"}}...{{end}} {{define "row"}}...{{end}} | Declares a named, reusable template within the same file |
{{template "name" pipeline}} {{template "row" .}} | Executes the named template, passing pipeline as its data |
{{block "name" pipeline}}...{{end}} {{block "row" .}}default{{end}} | Defines a template and executes it immediately, as a default another file's {{define}} can override |
{{/* comment */}} {{/* TODO */}} | A comment; produces no output |
{{pipeline | function}} {{.Name | upper}} | Pipes a value into a function or another pipeline stage, left to right |
Built-in functions
| Function | Description |
|---|---|
and / or / not {{if and .A .B}} | Boolean logic over their arguments |
eq / ne / lt / le / gt / ge {{if eq .Status "ok"}} | Comparison functions usable inside a pipeline |
len {{len .Items}} | Length of its argument: string, slice, map, or array |
index {{index .Items 0}} | Indexes into a slice, array, or map |
print / printf / println {{printf "%.2f" .Price}} | fmt.Sprint, fmt.Sprintf, and fmt.Sprintln, usable inside a template |
call {{call .Fn .Arg}} | Calls a function value with the given arguments |
Composition & introspection
| Function | Description |
|---|---|
(*Template) New(name string) *Template t.New("body") | Creates a new template associated with t, sharing its function map |
(*Template) Clone() (*Template, error) t.Clone() | Copies a template and every template associated with it |
(*Template) Lookup(name string) *Template t.Lookup("row") | Returns the associated template with the given name, or nil |
(*Template) Templates() []*Template t.Templates() | Returns every template associated with t, including t itself |
(*Template) DefinedTemplates() string t.DefinedTemplates() | A string listing every associated template's name, for debugging |
(*Template) Name() string t.Name() | The name t was created with |
(*Template) Option(opt ...string) *Template t.Option("missingkey=error") | Sets options such as "missingkey=error" for map lookups |
(*Template) Delims(left, right string) *Template t.Delims("<%", "%>") | Changes the action delimiters from the default {{ and }} |