Live: props from the server
A prop is a signal. When the server changes something, it writes one property, which wakes one binding, which updates one DOM node. It does not render a fragment and swap it in.
sess.Element("demo-todos").Set("items", list.Items())
// or several as one framesess.Batch(func() { sess.Element("demo-todos").Set("items", list.Items()) sess.Element("demo-todos").Set("filter", "done")})nothing sent yet The frames are scripted here because a static site has no Go server, but the client applying them is the one the Go module embeds. The runnable example in the module is a live Kanban board (`examples/todo`); the pattern is the same: one property write, every open tab.
Setting it up
Section titled “Setting it up”-
Create a server and mount it.
srv := live.New()defer srv.Close()mux := http.NewServeMux()live.Mount(mux, alacris.DefaultBase, srv)Mountregisters the runtime, the live client, and the two endpoints. Doing it by hand is fine; this only exists so the three cannot drift apart. -
Mint a session per page render and put its page id in the page. The capability is a cookie the call sets; see Sessions.
func (a *app) index(w http.ResponseWriter, r *http.Request) {// Sets the cookie that authorises this browser, so it has to run// before anything is written to w.sess := a.live.NewSession(w, r)sess.OnOpen(func(s *live.Session) { a.push(s) })cfg := alacris.Config{Modules: []string{"/web/components.js"},UI: true,Live: true,Page: sess.ID(),}// ... render the page with cfg} -
Give the elements you will patch an id. A patch addresses an element by its
id, and generated wrappers return an*Element, so:@components.Board(props).ID("board") -
Patch.
sess.Element("board").Set("items", list.Items())
The API
Section titled “The API”h := sess.Element("board")
h.Set("items", list.Items()) // a component proph.SetAttr("data-state", "ready") // an ordinary attribute; nil removes ith.Class("is-busy", true) // toggle a classh.SetHTML(ctx, "empty", tmpl) // replace the children of one sloth.Props(map[string]any{...}) // several props, one frameSet takes the JavaScript prop name from define() (maxCount, not
max-count) because it writes the DOM property rather than the attribute.
That is also why values need no encoding: they are JSON on the wire and become
real JavaScript values on arrival.
Batching
Section titled “Batching”Every Send is a frame. Wrap a group so the browser applies them together and
the page does not paint half an update:
sess.Batch(func() { sess.Element("board").Set("items", items) sess.Element("board").Set("columns", columns)})Sending to everyone
Section titled “Sending to everyone”srv.Broadcast(live.Prop("ticker", "price", 42.5))
for _, s := range srv.Sessions() { s.Element("board").Set("items", items) // when each page needs different data}This is what makes two open tabs agree without either of them polling.
When props are the wrong tool
Section titled “When props are the wrong tool”SetHTML replaces the light-DOM children assigned to one slot with markup the
server rendered:
h.SetHTML(ctx, ui.ChipSlotDefault, chipText("4 left"))Use it when the server owns the markup: a rendered document, a chunk of a report. For anything a component already models as a prop, a prop is smaller, does not touch the DOM the user is interacting with, and keeps rendering where the component put it.
What this costs
Section titled “What this costs”Sessions live in memory, so the server is stateful and needs session affinity behind a load balancer. See Deploying. The first two layers of this library have no dependency on any of it.
- Live: actions from the page: so the page can ask the server to change something.
- Sessions and reconnects: buffering, TTL, and
why
OnOpenis not optional.