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)));
}
Recommended architecture
- 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.