1d57a0962a4847df3fe01be4be2d1ab8a6dcb5af
Add missing marker options (offset, scale, opacity, opacityWhenCovered, className) and popup options (closeOnClick, closeOnMove, anchor, offset, className). Return MarkerHandle from AddMarker with OnClick, OnDragStart, OnDrag, OnDragEnd event methods. Return PopupHandle from ShowPopup with OnOpen, OnClose event methods. Upgrade drag signal writeback to fire during drag (throttled via requestAnimationFrame) in addition to dragend, enabling real-time position sync across clients.
Via
Real-time engine for building reactive web applications in pure Go.
Why Via?
The web became tangled in layers of JavaScript, build chains, and frameworks stacked on frameworks. Via takes a different path.
Philosophy
- No templates. No JavaScript. No transpilation. No hydration.
- Views are pure Go functions. HTML is composed with a type-safe DSL.
- A single SSE stream carries all reactivity — no WebSocket juggling, no polling.
Batteries included
- Automatic CSRF protection on every action call
- Token-bucket rate limiting (global defaults + per-action overrides)
- Cookie-based sessions backed by SQLite
- Pub/sub messaging with an embedded NATS backend
- Structured logging via zerolog
- Graceful shutdown with context draining
- Brotli compression out of the box
Example
package main
import (
"github.com/ryanhamamura/via"
"github.com/ryanhamamura/via/h"
)
type Counter struct{ Count int }
func main() {
v := via.New()
v.Page("/", func(c *via.Context) {
data := Counter{Count: 0}
step := c.Signal(1)
increment := c.Action(func() {
data.Count += step.Int()
c.Sync()
})
c.View(func() h.H {
return h.Div(
h.P(h.Textf("Count: %d", data.Count)),
h.Label(
h.Text("Update Step: "),
h.Input(h.Type("number"), step.Bind()),
),
h.Button(h.Text("Increment"), increment.OnClick()),
)
})
})
v.Start()
}
What's built in
- Reactive views + signals — bind state to the DOM; changes push over SSE automatically
- Components — self-contained subcontexts with their own data, actions, and signals
- Sessions — cookie-based, backed by SQLite via
scs - Pub/sub — embedded NATS server with JetStream; generic
Publish[T]/Subscribe[T]helpers - CSRF protection — automatic token generation and validation on every action
- Rate limiting — token-bucket algorithm, configurable globally and per-action
- Event handling —
OnClick,OnChange,OnSubmit,OnInput,OnFocus,OnBlur,OnMouseEnter,OnMouseLeave,OnScroll,OnDblClick,OnKeyDown, andOnKeyDownMapfor multi-key bindings - Timed routines —
OnIntervalauto-starts a ticker goroutine, returns a stop function, tied to context lifecycle - Redirects —
Redirect,ReplaceURL, and format-string variants - Plugin system —
func(v *V)hooks for integrating CSS/JS libraries - Structured logging — zerolog with configurable levels; console output in dev, JSON in production
- Graceful shutdown — listens for SIGINT/SIGTERM, drains contexts, closes pub/sub
- HTML DSL — the
hpackage provides type-safe Go-native HTML composition
Examples
The internal/examples/ directory contains 19 runnable examples:
chatroom · counter · countercomp · effectspike · greeter · keyboard · livereload · maplibre · middleware · nats-chatroom · pathparams · picocss · plugins · pubsub-crud · realtimechart · session · shakespeare · signup · spa
Experimental
Via is maturing — sessions, CSRF, rate limiting, pub/sub, and graceful shutdown are in place — but the API is still evolving. Expect breaking changes before v1.
Contributing
- Via is intentionally minimal and opinionated — and so is contributing.
- Fork, branch, build, tinker, submit a pull request.
- Keep every line purposeful.
- Share feedback: open an issue or start a discussion.
Credits
Via builds upon the work of these projects:
- Datastar — the hypermedia framework powering browser reactivity through signals and real-time HTML patches over SSE.
- Gomponents — Go-native HTML composition that powers the
via/hpackage.