Templ basics
Every astwerk page is a templ component, so the authoring model is templ's. These are the shapes astwerk pages are built from — each one is the entire feature. The full reference lives at templ.guide.
Components
A component is a function
// A component is a function; parameters are plain Go.
templ Greeting(name string) {
<p>Hello, { name }!</p>
}Parameters are plain Go values, so a component is called like a function and typed by the compiler.
Expressions and escaping
Escaping by default
// Expressions are HTML-escaped: & < > " ' all come out escaped,
// so a user-provided name cannot inject markup.
templ Profile(user User) {
<h1>{ user.Name }</h1>
<p>{ user.Bio }</p>
}{ expr } interpolates a value, HTML-escaped by default — & < > " ' all come out escaped, so a user-provided name cannot inject markup. Escaping is per context: element text, attribute, URL and CSS each get their own rules.
Composition and children
Nesting
// Components nest. A component that accepts children declares them
// with { children... } — callers wrap it instead of passing content in.
templ Layout(title string) {
<main>
<h1>{ title }</h1>
{ children... }
</main>
}
templ About() {
@Layout("About") {
<p>This paragraph is the children.</p>
}
}Components nest with @Component(...). A component that accepts children declares them with { children... }, and the caller wraps it instead of passing content in as a parameter — that is the shape starter/layout/base_layout.templ uses.
Conditionals and loops
Go, inline
// Conditionals and loops are Go, inline in the markup.
templ List(items []Item) {
if len(items) == 0 {
<p>Nothing here.</p>
} else {
<ul>
for _, it := range items {
<li>{ it.Label }</li>
}
</ul>
}
}if and for are Go, written inline in the markup. There is no template language to learn beyond what you already know.
Attributes
Escaping per context
// Attributes: a conditional attribute, a URL helper, and a CSS class
// helper — templ owns the escaping rules for each context.
templ Menu(current string) {
<button disabled?={ current == "" }>Submit</button>
<a href={ templ.URL("/docs/") }>Docs</a>
<a class={ templ.Class("active", current == "about") }>About</a>
}
// Trusted HTML is opt-in, never the default.
templ Article(htmlBody string) {
@templ.Raw(htmlBody)
}Attributes take Go expressions: disabled?={ cond } emits the attribute only when the condition holds, and helpers like templ.URL and templ.Class apply the right escaping for their context. Trusted HTML is the opt-in templ.Raw, never the default.