GO + HTMX + Templ
I have been using a javascript framework called Hono with HTMX, it’s a simple and easy to use framework that provides support for JSX, making it easy when working with HTMX.
Fortunately there is a similiar package in Go that works in a similiar fashion.
Usually gophers try sticking to what is available in the standard library, but the provided html templating package doesn’t cut it.
const tpl = `
<h1>{{.Title}}</h1>`
t, err := template.New("webpage").Parse(tpl)
err = t.Execute(os.Stdout, struct{ Title string }{"Hello, World!"})
While capable, it is clunky to use and is not as convenient as something like JSX.
Templ provides a similiar dx to JSX, you can write go code and html together in a templ file, like JSX allowing you to use language features to build your html, making it easier to create and read.
Templ supports template composition, we can create a base layout with our main html structure.
package views
templ Layout(title string) {
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width"/>
<script src="https://cdn.tailwindcss.com?plugins=forms,typography,aspect-ratio"></script>
<script src="https://unpkg.com/[email protected]"></script>
<script defer src="https://cdn.jsdelivr.net/npm/[email protected]/dist/cdn.min.js"></script>
<title>{ title }</title>
</head>
<body>
<main class="container mx-auto" id="main">
{ children... }
</main>
</body>
</html>
}
This is a .templ
, when compiled it will generate a go file and a function Layout
that can be imported from views
.
A templ function returns a type with a Render
method that can be called to render the html.
It takes a context and a writer, allowing you to write the html to a file or a http response.
type Component interface {
Render(ctx context.Context, w io.Writer) error
}
We will create a clock component that updates the time from the server every second.
package views
templ TimerPage() {
@Layout("Timer") {
<div>
<h1>Current time</h1>
<div hx-get="/timer" hx-trigger="every 1s"></div>
</div>
}
}
Here is our timer page, wrapped with our layout component.
Not the htmx attributes that will call /timer
endpoint every second.
package views
import "time"
templ Timer() {
<time>{time.Now().Format("15:04:05")}</time>
}
Our timer component will render the current server time.
Using the echo web framework, here is our server implementation:
func main() {
e := echo.New()
e.GET("/", internal.HomeHandler)
e.GET("/timer", internal.TimerHandler)
e.Logger.Fatal(e.Start(":8080"))
}
func HomeHandler(c echo.Context) error {
return views.TimerPage().Render(c.Request().Context(), c.Response())
}
func TimerHandler(c echo.Context) error {
return views.Timer().Render(c.Request().Context(), c.Response())
}
Install
Add the templ package to your go project:
go get github.com/a-h/templ
Install the templ cli:
go install github.com/a-h/templ/cmd/templ@latest
Compile your .templ
files:
templ generate
You can create a makefile to generate your templates and run your server:
default:
@templ generate
@go run ./cmd/app/main.go