astwerk

8. Interactivity

Static until now. The x package adds live behaviour without WASM: markers are templ components that render the current value and generate the JavaScript that keeps it live, in the same call. The counter below is running right now.

0

pages/home.templ:

templ
package pages

import x "github.com/LukasDerBaum42/astwerk/x"

// count is the site's one piece of state. It is named so scripts can read it;
// every page that renders counter() shares it.
var count = x.Named("count", 0)

templ Home(title string, path string, prefix string) {
	@Layout(title, path, prefix) {
		<h1>My Site</h1>
		<p>A portfolio built with astwerk.</p>
		@x.Document(counter())
	}
}

// counter is a live widget: the markers below render the value and generate
// the JavaScript that keeps it in sync.
templ counter() {
	<div class="counter">
		@x.Text(count)
		@x.El("button", x.On("click", count.Set(count.Add(1)))) {
			+
		}
	</div>
}

x.Named creates the state under a fixed name, so scripts can read it; x.Text renders the value and generates the binding that keeps it in sync, and x.On does the same for the handler. x.Document emits the runtime and state declarations before its body and the bindings after it. View source on this page: the bindings are embedded right here, and no .wasm was downloaded. Disable JavaScript and the value still renders — it was written statically at build time.

The full marker set — bindings, forms, lists, effects — is in x — compiled reactive markup.

What does @x.Text(count) do?

Try it. Change the counter's initial value from 0 to 5 and rebuild.

What you should see

The button shows 5 before any JavaScript runs — the value is written into the HTML at build time, and the generated script keeps it in sync.

With JavaScript disabled, what does a page with x markers show?