Realtime

HTMX can subscribe to live updates over WebSockets or Server-Sent Events. With StreetJS the key idea is: render HTML fragments on the server and push them — the client just swaps them in. No client-side JSON-to-DOM code.

WebSockets

HTMX’s ws extension connects to a socket and swaps incoming HTML:

1
2
3
4
<div hx-ext="ws" ws-connect="/ws">
  <ul id="messages"></ul>
  <form ws-send><input name="msg" autocomplete="off"></form>
</div>

Server side, StreetJS already ships a bounded WebSocket server with heartbeat and auth-on-upgrade. Broadcast rendered partials (not JSON) to subscribers:

1
2
3
// when a message arrives, render the partial and broadcast HTML
const html = engine.partial('message', { user, body });
hub.broadcast('room:1', `<ul id="messages" hx-swap-oob="beforeend">${html}</ul>`);

hx-swap-oob lets a pushed fragment update a target by id, out of band.

Server-Sent Events (SSE)

For one-way streams (notifications, live dashboards), SSE is simpler and reuses core SSE:

1
<div hx-ext="sse" sse-connect="/events" sse-swap="notification"></div>
1
2
3
4
5
@Get('/events')
async events(ctx: StreetContext) {
  const sse = ctx.sse();                       // core SSE helper
  timer.on('tick', () => sse.send('notification', engine.partial('toast', data)));
}
  • Initial page: a normal ctx.htmx.view(...) render.
  • Live updates: WebSockets for bidirectional (chat), SSE for one-way (dashboards).
  • Always send HTML, not JSON — HTMX swaps it directly.
  • Multi-instance fan-out: add @streetjs/plugin-redis.

See the core Realtime guide for the WebSocket/SSE APIs.

Next: Deployment.