You are reading the docs for v0.8. Read the latest (v0.10)
Glossary
The terms these docs use. Each links to the section that teaches it and to its API row where one exists.
On this page
#Action
A method of a composition, func(*via.Ctx) or func(*via.Ctx, V) bound with on.WithArg, attached to a DOM event with package on. The browser POSTs to it; via runs it on the server, then OnReload, then re-renders the unit and answers with the patch. It returns nothing: a failure the user can fix goes into state, and a panic is a 500.
See: Actions, Actions › Action signatures, on.Click, on.WithArg.
#Composition
A Go struct with a View() h.H method. Its fields are its state, its methods are its actions, and the optional hooks OnInit, OnReload and PageMeta opt it into lifecycle phases. via.Mount serves one at a path and via.Child renders one as a field of another; both take it by value.
See: Compositions › A composition is a struct, Getting started › The parts, via.Mount, via.Child.
#CSP
The Content-Security-Policy header via sends with each document. It is derived once per mount from the router's via.WithHead assets and the page's Meta.Assets, and admits via's own inline scripts by hash. script-src always carries 'unsafe-eval' for Datastar's expressions.
See: Sessions & security › Content-Security-Policy, Islands › Libraries from another origin, via.Assets.
#Datastar
The browser runtime via targets, vendored in the via module and served by the router. via emits the data-* attributes and the patches; Datastar evaluates the expressions, sends signals with each action, and morphs patches into the page. You do not write Datastar by hand, but its reconnect and morph behaviour is via's.
See: Why Via › What you get, Why Via › What it costs.
#expr
The package that composes the JavaScript expressions Datastar evaluates in the browser: a signal reference, a comparison, an assignment, a call. An expr.Expr goes into an on.*CS binder or an h.Data* attribute. Everything is checked except expr.Raw and the text of expr.Rawf, which are emitted verbatim.
See: Signals › Expressions, expr.Expr, expr.Val.
#Island
A container via renders once and then leaves to your JavaScript. h.DataIgnoreMorph keeps later patches out of its subtree, and Go feeds it by setting signals the script reads through h.DataEffect.
See: Islands › The island contract, h.DataIgnoreMorph, h.DataEffect.
#Listen
via.Ctx.Listen subscribes a unit to a Topic: each published value runs the handler on the unit's own goroutine, then the unit re-renders and pushes. Valid only in OnInit, and it makes the unit live. The subscription is taken when the stream connects and stopped when it closes.
See: Live state › Topics, via.Ctx.Listen.
#Live unit
A composition, the mounted root or a Child, that calls via.Ctx.Tick or via.Ctx.Listen in OnInit, or renders a via.State.Display or a via.List.Each. Its instance stays in memory for the life of the tab's SSE stream, and every callback on it runs on that stream's one goroutine. A live unit may not contain another live unit.
See: Live state › A page is plain until a unit goes live.
#Meta.Assets
The Assets field of via.Meta: the scripts and styles a page loads. It decides the mount's CSP, so it must be a constant of the type: via reads it at Mount and on every document render, and panics if two readings disagree.
See: Islands › The island contract, Sessions & security › Content-Security-Policy, via.Meta, via.Assets.
#Morph
How Datastar applies an element patch: it matches incoming elements to the live ones by id and updates them in place, so focus, scroll position and element identity survive. A subtree whose old and new versions both carry h.DataIgnoreMorph is left alone.
See: Islands › The island contract, h.DataIgnoreMorph.
#OnConnect
via.Ctx.OnConnect registers a function that runs once when the unit's stream opens, after every Listen has subscribed. Register it in OnInit. It does not make a unit live, so on a plain unit it never runs.
See: Live state › Presence, Islands › Stopping a producer on disconnect, via.Ctx.OnConnect.
#OnDispose
via.Ctx.OnDispose registers a teardown function that runs when the unit's connection closes: stop a subscription, release a producer. Register it in OnInit. It runs only on a unit something else made live.
See: Live state › Presence, Islands › Stopping a producer on disconnect, via.Ctx.OnDispose.
#OnInit
OnInit(*via.Ctx) error runs before the View on every request that renders the unit, page or child, including each plain action. It loads request and session data into fields and registers Tick, Listen, OnConnect and OnDispose. It may via.Ctx.Redirect or return via.ErrNotFound for a 404; any other error is a 500. On a live unit it runs once, at connect, not per action.
See: Compositions › Lifecycle hooks.
#OnReload
OnReload(*via.Ctx) error runs after one of the unit's actions and before the render that answers it, on plain and live units alike: it re-reads what the handler wrote. It is skipped when the handler called Redirect, and Tick and Listen are no-ops inside it.
See: Actions › What an action body can do, Compositions › Lifecycle hooks.
#PageMeta
PageMeta() via.Meta names the document: title, description, social cards and assets. Only the mounted root's counts. It must be pure: via reads it at Mount and on every document render, after OnInit and OnReload, and never on an SSE push.
See: Compositions › Lifecycle hooks, via.Meta.
#Plain vs live page
A page streams if and only if it contains a live unit. A plain page is request and response: each GET and action POST gets a fresh copy of the mounted value, and an action's answer is the POST's own body. A live page also holds one SSE stream per tab, and its actions answer over that stream. The render that served the page decides; an action cannot make a plain page live.
See: Live state › A page is plain until a unit goes live, Actions › Concurrency.
#Positional child key
The key via gives each Child: its position among its parent's Child calls, joined to the parent's key (0, 0-0). The child's container id, signal prefix and action address all derive from it, so it must be the same on every render for the life of a connection. A via.When around a Child shifts its later siblings, so it may depend only on data fixed by OnInit or the field literal.
See: Compositions › Children and keys, Compositions › Conditional children shift keys, via.Child.
#PostForm vs on.Submit
on.Submit posts the page's signals through Datastar and the answer patches the page in place. via.PostForm renders a native multipart form: the submit is a browser navigation, the handler reads ctx.Request().FormValue and FormFile, and a Redirect answers 303. Use PostForm for sign-in, uploads and flows that end in a redirect.
See: Actions › Forms: on.Submit or PostForm, on.Submit, via.PostForm.
#Ref
via.Signal.Ref and via.SignalCS.Ref return the signal's Datastar name as an expr.Expr: $count for a field Count, $_open for a SignalCS Open. Use it in client expressions and hand-written data-* attributes. A signal reached through a pointer, slice, array or map has no name, and Ref on it panics. State has no Ref.
See: Signals › Expressions, Signals › Wire names, via.Signal.Ref, via.SignalCS.Ref.
#Session
The per-browser value bag behind via.Ctx.Session: one JSON value per session, resolved from a signed cookie and created on the first write, so an app that stores nothing sets no cookie. Expiry is an idle window, 24 hours by default, that slides with use. Ids never rotate on their own: call via.Session.Rotate at every login, logout and privilege change.
See: Sessions & security › Sessions and Rotate, Sessions & security › The session cookie, via.Session, via.Ctx.Session.
#SessionStore
The interface session data lives behind between requests: a map of serialized blobs. The default, via.MemorySessionStore, is process-local, so a restart logs everyone out and a second pod sees nothing. via.WithSessionStore swaps in a shared backend; implement via.VersionedSessionStore as well or two concurrent writes can lose one.
See: Sessions & security › Session stores, Deploy › Sessions that survive a restart, via.SessionStore, via.WithSessionStore.
#Signal
via.Signal, a field whose value lives in the browser as a Datastar signal named after the field. It is sent with every action and the server can read and Set it; T must round-trip through JSON. via.Signal.Bind ties it to an input and via.Signal.Display renders it as text.
See: Signals › Where state lives, Signals › Binding and display, via.Signal.
#SignalCS
via.SignalCS, a browser-only signal. Its name starts with _, which Datastar leaves out of every POST, and it has no Get or Set: the server only picks its starting value. Drive it with the on.*CS binders and expr.
See: Signals › Client-only signals, via.SignalCS.
#SSE
Server-Sent Events: the one-way HTTP stream via opens for a tab whose page has a live unit. One stream per tab carries every live unit's element and signal patches; there are no WebSockets. A dropped stream reconnects, and a reconnect is a new connection that runs OnInit again.
See: Live state › A page is plain until a unit goes live, Live state › Connection lifecycle, via.WithMaxSSEConn.
#State
via.State, server-only unit state. It never reaches the browser as a signal: via.State.Display renders it as text, marks the unit live, and each Set is pushed as a patch. via.State.Get alone does not make a unit live. Mirror it into a Signal when client code must react to it.
See: Live state › Server state, via.State, via.StateOf.
#Tick
via.Ctx.Tick runs a function every interval for the life of the unit's connection, on the unit's goroutine, then re-renders and pushes. Valid only in OnInit, and it makes the unit live.
See: Live state › Timers, via.Ctx.Tick.
#Topic
topic.Topic, an in-process fan-out broker: one Publish reaches every subscriber, and Publish is safe from any goroutine. It is how another tab's action or a goroutine of yours reaches a live unit, through Listen. Delivery stays in one process, with no durability, replay or cross-pod delivery.
See: Live state › Topics, Deploy › State across pods, topic.New, topic.Topic.Publish.
#View
View() h.H, the one required method of a composition. It is pure and takes no context: it reads fields and returns markup, and via calls it on every render, so request reads and side effects belong in OnInit or an action. via.Mount rejects a type without one at compile time.
See: Getting started › The parts, Compositions › A composition is a struct.
#Wire pane
A go-via.dev feature, not part of via: the pane under each demo card that lists the demo's action POSTs, their statuses, and the SSE patches it receives.