Skip to content

v0.14.0

Choose a tag to compare

@ryanhamamura ryanhamamura released this 12 Feb 23:55
· 37 commits to main since this release

SPA-like navigation with view transitions

Navigate between pages without full page loads. A single persistent Context resets its page-specific state (signals, actions, intervals, subscriptions) on navigate while preserving the SSE connection — no white flash, no reconnection delay.

v.Layout(func(content func() h.H) h.H {
    return h.Div(
        h.Nav(
            h.A(h.Href("/"), h.Text("Home")),
            h.A(h.Href("/dashboard"), h.Text("Dashboard")),
        ),
        h.Main(content()),
    )
})

v.Page("/dashboard", func(c *via.Context) {
    goHome := c.Action(func() { c.Navigate("/", false) })

    c.View(func() h.H {
        return h.Button(h.Text("Go Home"), goHome.OnClick())
    })
})

How navigation works

  • <a href="/path"> links — automatically intercepted by Via's injected JS. Opt out individual links with data-via-no-boost
  • c.Navigate("/path") — programmatic SPA navigation from action handlers
  • Browser back/forward — handled via popstate
  • c.Redirect("/path") — unchanged, still does a full page load (escape hatch, external URLs)

New APIs

  • v.Layout(func(func() h.H) h.H) — optional layout function that wraps every page's view in a shared shell (nav, footer, etc.)
  • c.Navigate(path, popstate) — SPA navigation that resets page state and runs the target page's init function over the existing SSE connection
  • h.DataViewTransition(name) — sets view-transition-name on an element for cross-page animation

What resets on navigate

Signals, actions, OnInterval goroutines, pub/sub subscriptions, and fields are all torn down and recreated by the target page's init function. The SSE connection, CSRF token, and session persist.

View Transition API

Navigate uses Datastar's WithViewTransitions() to animate content swaps. Tag elements with h.DataViewTransition("name") to animate matching elements between pages.

Full Changelog: v0.13.0...v0.14.0