Getting started

From install to a rendered fragment in five steps. (This walkthrough is compiled and run by the repository's test suite โ€” it cannot rot.)

1. Install

go install github.com/go-monolith/ghtmx/cmd/ghtmx@latest
go install golang.org/x/tools/gopls@latest   # embedded-Go support in the LSP

2. Create a module

mkdir hello && cd hello
go mod init example.com/hello

3. Write the app

Create main.go โ€” routes are ordinary net/http registrations; the route discoverer reads them at build time:

package main

import (
	"log"
	"net/http"
)

func Index(w http.ResponseWriter, r *http.Request) {
	if err := page("world").Render(r.Context(), w); err != nil {
		log.Printf("render: %v", err)
	}
}

func Greeting(w http.ResponseWriter, r *http.Request) {
	if err := greetingFragment("htmx").RenderFragment(r.Context(), w); err != nil {
		log.Printf("render: %v", err)
	}
}

func routes() *http.ServeMux {
	mux := http.NewServeMux()
	mux.HandleFunc("GET /{$}", Index)
	mux.HandleFunc("GET /greeting", Greeting)
	return mux
}

func main() {
	log.Println("listening on :8080")
	log.Fatal(http.ListenAndServe(":8080", routes()))
}

Create page.ghtmx โ€” the button binds the Greeting handler by symbol (the compiler folds its route path in statically), and the greeting is a fragment with both an inline and a standalone entry point:

package main

import "example.com/hello/ghtmxgen"

templ page(name string) {
	<!DOCTYPE html>
	<html>
		<head>
			@ghtmxgen.HTMXScript()
		</head>
		<body>
			<button hx-get={ Greeting } hx-target="#greeting" hx-swap="outerHTML">Greet</button>
			@greeting(name)
		</body>
	</html>
}

fragment greeting(name string) {
	<p id="greeting">Hello, { name }!</p>
}

4. Generate and tidy

ghtmx generate
go mod tidy

Generation writes page_ghtmx.go beside the template and the central ghtmxgen package (the pinned htmx script helper, and โ€” for parameterised routes โ€” typed URL constructors). If you rename Greeting later, both the registration and the binding break the build: that is the point.

Two expected notices on this first run: a version-check note about ghtmx not being in go.mod yet (the tidy that follows fixes it), and GHTMX-W0104 for the GET / page route, which is navigated to rather than bound โ€” full-page routes always warn like this.

5. Run it โ€” and render a fragment

go run .

A browser on http://localhost:8080 shows the page; clicking Greet swaps in the fragment. The same standalone fragment renders directly:

curl -H "HX-Request: true" http://localhost:8080/greeting
<p id="greeting">Hello, htmx!</p>

That response is byte-identical to the fragment embedded in the full page โ€” the compile-time fragment guarantee.

Where next

  • ghtmx generate -watch -cmd 'go run .' -proxy http://localhost:8080 gives live reload with a dev proxy.
  • The Syntax specification covers every construct; examples/crud in the repository is the full reference application with events, typed constructors, and inline editing.