Claude
Skills
Sign in
Back

templ

Included with Lifetime
$97 forever

templ templating: syntax, components, attributes, styling, and JavaScript integration. Invoke when task involves any interaction with templ — writing .templ files, creating components, composing templates, testing rendered output, or understanding templ syntax.

Productivity

What this skill does


# templ

Type-safe Go HTML templating. Components defined in `.templ` files compile to Go functions returning `templ.Component`
via `templ generate`. Outside `templ` blocks = ordinary Go. Inside = templ syntax.

## References

Extended examples and detailed patterns for the rules below:

- `${CLAUDE_SKILL_DIR}/references/syntax.md` — Template syntax, expressions, control flow, raw Go blocks: file
  structure, expression types, error propagation, auto-escaping, control flow examples
- `${CLAUDE_SKILL_DIR}/references/components.md` — Component definition, composition, children, fragments: component
  interface, `@` composition, children context API, render-once, fragment rendering
- `${CLAUDE_SKILL_DIR}/references/attributes.md` — Boolean, conditional, spread attributes, key expressions: attribute
  types with code examples, spread value behavior, URL/JS/JSON attribute patterns
- `${CLAUDE_SKILL_DIR}/references/patterns.md` — View models, layouts, context, html/template interop: props struct
  pattern, nested layouts, context helpers with middleware, Go template interop
- `${CLAUDE_SKILL_DIR}/references/javascript.md` — Script/style tags, inline events, data passing to JS:
  JSFuncCall/JSExpression/JSONString/JSONScript API, IIFE pattern, method summary
- `${CLAUDE_SKILL_DIR}/references/styling.md` — Class patterns, CSS components, style attributes: class toggling
  approaches (KV, maps, raw Go), CSS component scoping, style sanitization

## Syntax

### Expressions `{ }`

Output Go values inside templ blocks. Content is automatically HTML-escaped for XSS safety.

Supported types: `string`, numbers (`int`, `uint`, `float32`, `complex64`, etc.), booleans, and any type based on these
(e.g. `type Name string`).

Use variables, field access, and function calls: `{ name }`, `{ p.Name }`, `{ strings.ToUpper(name) }`,
`{ fmt.Sprintf("%d items", count) }`.

Functions returning `(T, error)` propagate errors to `Render()` with source location info.

### Elements

All tags must close. Write `<br/>` not `<br>`. templ is aware of void elements and strips `/` in output HTML, but source
must always include it.

templ automatically minifies HTML output.

### Control Flow

Use bare Go keywords — `if`/`else`, `switch`/`case`, `for`/`range`. No special syntax.

Text starting with `if`, `for`, or `switch` triggers the parser. Two solutions:

- Wrap as expression: `{ "if you need this text" }`
- Capitalize the keyword: `If you need this text`

### Raw Go `{{ }}`

Scoped Go statements inside templ blocks for intermediate variables.

```templ
{{ total := calculateTotal(items) }}
<p>Total: { fmt.Sprintf("%d", total) }</p>
```

Use `{{ }}` to avoid calling expensive functions twice — cache results in a variable.

### Comments

- **Inside templ blocks**: use HTML comments `<!-- -->` (rendered to output). No nesting.
- **Outside templ blocks**: use Go comments `//` (not rendered).

### Implicit Variables

Every component has two implicit variables:

- **`ctx`** — `context.Context` from the `Render` call. Available in all components.
- **`children`** — content passed via `@component() { ... }`. Access with `{ children... }`.

## Components

### Definition and Visibility

Components compile to Go functions returning `templ.Component`. Follow Go visibility rules: uppercase name = exported,
lowercase = unexported.

The `templ.Component` interface: `Render(ctx context.Context, w io.Writer) error`.

**Partial output warning**: a component may write partial output to `io.Writer` before returning an error. To guarantee
all-or-nothing, render to a buffer first.

### Composition

Call components with `@` prefix: `@header()`, `@components.Header()`, `@nav.Item("Home", "/")`.

### Children

Pass content to a component with `@layout() { <p>children</p> }`. Receive with `{ children... }` in the component body.

In code-only components, manage children via context: `templ.WithChildren`, `templ.GetChildren`, `templ.ClearChildren`.

### Components as Parameters

Pass components as values via `templ.Component` type parameters, render with `@param`.

### Joining Components

Aggregate multiple components into one with `@templ.Join(header(), nav(), footer())`.

### Method Components

Attach components to types when a component has many configuration options — struct fields are self-documenting and can
have defaults. Call inline: `@Button{Text: "Submit", Variant: "primary"}.Render()`.

### Code-Only Components

Implement `templ.Component` in pure Go using `templ.ComponentFunc`:

```go
func button(text string) templ.Component {
    return templ.ComponentFunc(func(ctx context.Context, w io.Writer) error {
        _, err := io.WriteString(w, "<button>"+templ.EscapeString(text)+"</button>")
        return err
    })
}
```

**In code-only components, you must escape HTML yourself** with `templ.EscapeString`. Auto- escaping only applies inside
`.templ` files.

### Render-Once

Ensure content renders once per HTTP response (or per context). Common use: shared `<script>`, `<style>`, or `<link>`
tags.

1. Declare handles at **package level**: `var h = templ.NewOnceHandle()`.
2. Use in component: `@h.Once() { <script src="..."></script> }`.
3. **Never inline** `@templ.NewOnceHandle().Once()` — creates a new handle each call, content renders every time,
   defeating the purpose.

For cross-package shared dependencies, export render-once components — wrap the handle and `Once()` call in an exported
templ function, then call from any package.

### Fragments

Render subsections of templates, discarding all other output. The full template still executes (all logic runs), but
only the fragment's output is written.

- Define: `@templ.Fragment("content") { <div>fragment</div> }`
- Render via HTTP: `templ.Handler(Page(), templ.WithFragments("content"))`
- Render without HTTP: `templ.RenderFragments(ctx, w, Page(), "content")`

**Custom fragment keys**: use typed keys (`type contentKey struct{}`) to avoid name clashes.

**Nested fragments**: selecting outer includes inner. Useful for partial page updates (e.g. with htmx).

## Attributes

### Constant Attributes

Standard HTML attributes with double quotes: `<p class="container" data-testid="p">`.

### Dynamic String Attributes

Set to Go expressions with `{ }`: `<div class={ className }>`, `<div data-id={ fmt.Sprintf("item-%d", id) }>`.

String values are automatically HTML-attribute-encoded. Functions returning `(string, error)` propagate errors to
`Render()`.

### Boolean Attributes `?=`

Presence/absence based on Go boolean: `<input disabled?={ isDisabled }/>`, `<button hidden?={ !showButton }/>`. Static
booleans: `<hr noshade/>`.

### Conditional Attributes

Use `if` inside element open tags to conditionally add attributes. The conditional attribute **replaces** the earlier
one of the same name — include base classes in both branches.

### Attribute Key Expressions

Dynamically set the attribute key: `<p { "data-" + suffix }="value">`.

**Warning**: key expressions don't get type-specific handling. URL attributes (`href`) and event handlers (`on*`)
defined via key expressions are treated as plain strings without special sanitization.

### Spread Attributes

Append a dynamic map with `{ attrs... }` where `attrs` is `templ.Attributes` (`map[string]any`).

Value rendering by type:

- `string` → `name="value"`
- `bool` → `name` (if true) or omitted (if false)
- `templ.KeyValue[string, bool]` → `name="value"` if bool is true
- `templ.KeyValue[bool, bool]` → `name` if both bools are true

Spread attributes can be conditional using `if` inside element open tags.

**Never mutate a global `templ.Attributes` var** — create fresh `templ.Attributes{}` per render call.

## Security

### HTML Auto-Escaping

All expressions `{ }` are HTML-escaped. Use `@templ.Raw()` **only** for trusted content.

### URL Sanitization

`href`, `src`, `action` auto-sanitize dynamic values — `javascript:` schemes become
`about:invalid#TemplFailedSanitizationURL`. Bypass with `templ.SafeURL()` for t

Related in Productivity