Components and Syntax

A .templ file is ordinary Go plus component declarations. Outside components you write normal Go (package, imports, helper functions). Inside, markup mixes with expressions, and templ generate turns the whole thing into a Go file the compiler checks.

Defining a component

package views

import "fmt"

templ greeting(name string) {
    <p>Hello, { fmt.Sprintf("%s!", name) }</p>
}

After templ generate, this becomes a Go function:

func greeting(name string) templ.Component

Every component satisfies one interface (runtime.go):

type Component interface {
    Render(ctx context.Context, w io.Writer) error
}

templ.ComponentFunc adapts an ordinary closure into a Component, which is handy for small inline pieces.

Expressions

{ expr } inserts a Go expression into text content or attribute values. Output is HTML-escaped automatically.

templ userCard(name string, admin bool) {
    <div class="card">
        <h2>{ name }</h2>
        <span data-admin={ fmt.Sprint(admin) }></span>
    </div>
}

Gotcha: Escaping applies to every expression. To emit trusted HTML you must opt out explicitly with templ.Raw - see Security and Scripts.

Control flow is Go

There is no template mini-language. Use if, switch, and for directly:

templ items(items []string) {
    if len(items) == 0 {
        <p>Nothing here.</p>
    } else {
        <ul>
            for _, item := range items {
                <li>{ item }</li>
            }
        </ul>
    }
}

Composition and children

Call another component with @. Components can take other components as parameters, which is how layouts work:

templ layout(contents templ.Component) {
    <html>
        <body>
            @contents
        </body>
    </html>
}

templ paragraph(text string) {
    <p>{ text }</p>
}

templ page() {
    @layout(paragraph("hello"))
}

{ children... } is the alternative: it renders whatever children the caller passed in.

templ.Join, KV, Once, Raw

HelperPurposeWhere
templ.Join(components...)Render several components as onejoin.go
templ.KV(name string, cond bool)Conditional entry in a class={ ... } listruntime.go
templ.Once()Render-once semantics for content that would otherwise repeatonce.go
templ.Raw(html)Emit unescaped HTML (escape hatch)runtime.go
templ badge(label string, active bool) {
    <span class={ "badge", templ.KV("badge-active", active) }>{ label }</span>
}

Tip: Reach for templ.Join when a component needs to return several sibling elements - it composes children without introducing a wrapper element.