astwerk

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

templ
// 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

templ
// 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

templ
// 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

templ
// 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

templ
// 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.