Attribute bindings
The WASM twin of the compiled-markup attribute bindings: four one-property bindings — href, class, disabled, style — each driven by its own signal. Change a signal and exactly that property updates, nothing else re-renders. The compiled-markup version is Attribute bindings.
How it works
State
url := reactive.NewSignal("https://templ.guide")
active := reactive.NewSignal(true)
busy := reactive.NewSignal(false)
colour := reactive.NewSignal("#4f7cff")One signal per property the demo touches: the link target, the class, the disabled flag and the colour.
The elements
reactive.BindAttr(root.Find("[data-bind-href]"), "href", url.Get)
reactive.BindClass(root.Find("[data-bind-class]"), "on", active.Get)
reactive.BindAttr(root.Find("[data-bind-disabled]"), "disabled", func() string {
if busy.Get() {
return "disabled"
}
return "" // empty removes the attribute
})
reactive.BindStyle(root.Find("[data-bind-style]"), "color", colour.Get)Each binding owns one property of one element. BindAttr sets a string attribute and removes it when the value is empty; BindClass toggles one class; BindStyle sets one CSS property.
The buttons
reactive.On(root.Find("[data-toggle-class]"), "click", func(wasmwrap.Event) {
active.Update(func(v bool) bool { return !v })
})
reactive.On(root.Find("[data-toggle-disabled]"), "click", func(wasmwrap.Event) {
busy.Update(func(v bool) bool { return !v })
})
reactive.On(root.Find("[data-recolour]"), "click", func(wasmwrap.Event) {
colour.Set("#ff4f7c")
})
reactive.On(root.Find("[data-retarget]"), "click", func(wasmwrap.Event) {
url.Set("https://pkg.go.dev/github.com/LukasDerBaum42/astwerk")
})Each button writes its signal — Update toggles a bool, Set stores a constant. Because each binding owns its property, changing one signal updates exactly that element's property — nothing else re-renders.
Full source
url := reactive.NewSignal("https://templ.guide")
active := reactive.NewSignal(true)
busy := reactive.NewSignal(false)
colour := reactive.NewSignal("#4f7cff")
reactive.Hydrate("#bindings-demo", func(root wasmwrap.Element) {
reactive.BindAttr(root.Find("[data-bind-href]"), "href", url.Get)
reactive.BindClass(root.Find("[data-bind-class]"), "on", active.Get)
reactive.BindAttr(root.Find("[data-bind-disabled]"), "disabled", func() string {
if busy.Get() {
return "disabled"
}
return ""
})
reactive.BindStyle(root.Find("[data-bind-style]"), "color", colour.Get)
reactive.On(root.Find("[data-toggle-class]"), "click", func(wasmwrap.Event) {
active.Update(func(v bool) bool { return !v })
})
reactive.On(root.Find("[data-toggle-disabled]"), "click", func(wasmwrap.Event) {
busy.Update(func(v bool) bool { return !v })
})
reactive.On(root.Find("[data-recolour]"), "click", func(wasmwrap.Event) {
colour.Set("#ff4f7c")
})
reactive.On(root.Find("[data-retarget]"), "click", func(wasmwrap.Event) {
url.Set("https://pkg.go.dev/github.com/LukasDerBaum42/astwerk")
})
})How this demo runs
scripts/demo.go is compiled to demo.wasm by CompileFrom and loaded by WasmScript — see Scripts & WebAssembly. Without WebAssembly the page still renders; only the bindings stay put.