Ecosystem

templ is a small core by design. The ecosystem fills in components, interactivity, and tooling.

Component libraries

  • templUI - component library built on templ + Tailwind + vanilla JavaScript
  • shadcn-templ - port of the shadcn/ui look to templ; if you already know shadcn/ui, start here (same component names, same props)
  • awesome-templ - curated list of libraries and examples

These cover the “I just need a decent admin panel” gap that a small core deliberately leaves open.

Interactivity

templ ships no JavaScript runtime. The common pairings:

  • htmx - HTML-over-the-wire partial updates; templ has native fragment support, see Use with htmx
  • Datastar - the other frequently paired hypermedia library

Both work because templ renders plain HTML from ordinary handlers; nothing about the output is framework-specific.

Tooling and docs

  • Official documentation at templ.guide, including an LLM-friendly docs page for agent consumption
  • The CLI covers generate, fmt, and lsp; IDE support is documented for VS Code and Neovim
  • Formatting and generation respect .templignore_fmt and .templignore_generate glob files for excluding paths
  • Testing: expectation tests with io.Pipe + goquery against data-testid attributes, snapshot testing as an alternative, and templ.WithChildren for injecting children in tests
  • Hosting guides cover Docker and AWS Lambda (see Deploy in Docker)

Routers and middleware

templ is router-agnostic; the repo ships worked integration examples for chi, echo, gin, and fiber (examples/integration-*). Components render through plain http.Handlers, so standard middleware applies. On Go 1.25+, CSRF protection is built into the standard library (http.CrossOriginProtection), which closes the biggest historical gap versus framework-bundled auth.

Testing stack

The documented expectation-testing shape: render through an io.Pipe, parse with goquery, assert on data-testid attributes:

func TestGreeting(t *testing.T) {
    r, w := io.Pipe()
    go func() {
        w.CloseWithError(greeting("templ").Render(context.Background(), w))
    }()
    doc, err := goquery.NewDocumentFromReader(r)
    if err != nil {
        t.Fatal(err)
    }
    if got := doc.Find(`[data-testid="greeting"]`).Text(); got == "" {
        t.Fatal("greeting element not found")
    }
}

No HTTP server needed - components write to any writer, so the test is just a render plus a parse. templ.WithChildren injects children when the component under test expects them.

Rendering performance

Rendered output comes from pooled buffers and constant writes, so page caching is the usual lever if you need more - see Cache Rendered Pages and the Rendering Model.

Lab notes

  • theok: templ is the candidate for folding the public site into a single Go binary.