Theme
/
Theory

Why Templ — type safety and generation

Lesson 1 ended with Home writing HTML as a raw Go string. That works for one line and falls apart for a real page: no type-checking, a missing </div> compiles fine and breaks at runtime, and there's no way to share a header across pages. We need real templates — and we want them type-safe.

Templ compiles HTML templates into Go functions. You write .templ files; a generator turns each into a _templ.go file of plain Go. The payoff: a template is type-checked like any other Go code. Pass an int where the template expects a string and it won't compile — the error is at build time, at the exact line, not a blank space on a live page.

The generation step. After you write or edit a .templ file, you run:

templ generate

That regenerates the _templ.go files. We commit the generated .go alongside the .templ — so the app builds and deploys with only the Go toolchain; templ is needed only when you change a template. (This mirrors how a real project keeps generated code in the repo so CI doesn't need every code-gen tool installed.)

Gotcha — the stale-template trap. Edit a .templ, forget to run templ generate, reload the page, and you see the old output — because the running binary uses the committed _templ.go, not your edited .templ. It looks like your change did nothing. It's not broken; it's un-generated. The habit that saves you: edit .templtempl generate → rebuild. (Many editors run it on save.)

HTMX, vendored — no build step. SignFlow uses HTMX for interactivity later (a form that posts without a full page reload). HTMX is a single JavaScript file; we vendor it under static/js/htmx.min.js and link it from the layout. No npm, no bundler, no CDN dependency at runtime — the file ships inside the binary. The whole front end is: server-rendered HTML + one vendored script.

This lesson. You'll build a shared Layout, a Home page that slots into it, a tiny render helper, and wire Home to render the template instead of a string. Same page as lesson 1 — but now the compiler checks it, and it finally has some CSS.