HTML over WebSockets: real-time SPAs with barely any JavaScript
HTML over WebSockets: Creating Real-Time SPAs with Minimal JavaScript
Building a modern Single-page Application (SPA) often feels like solving a fragmented puzzle. You typically need a JavaScript framework to handle the view, a separate API to serve JSON data, and two distinct codebases that must stay synchronized via strict contracts.
There is a different path—one that isn't entirely new but has seen a resurgence: HTML over WebSockets.
The Core Concept
Instead of transmitting JSON and forcing the browser to construct the HTML, the server delivers the fully rendered HTML. The client's only job is to place that HTML into the correct location in the DOM.
By keeping all rendering logic on the Back-End, you use a single language and eliminate the need for complex API contracts. The primary differentiator between various implementations is how that HTML is transported, which affects latency and bidirectionality.
Transport Comparison
| Method | Technology Examples | Communication Style | Nature |
|---|---|---|---|
| HTTP | htmx, Unicorn | Request Response | Stateless |
| SSE | Datastar | Server Client | One-way stream |
| WebSockets | Phoenix LiveView, Django LiveView | Bidirectional | Permanent channel |
This article focuses specifically on HTML over WebSockets, the real-time variant that allows for SPA functionality with almost no custom JavaScript.
The Origin Story
The momentum for this approach spiked at ElixirConf 2019, where Chris McCord (creator of the Phoenix framework) introduced LiveView. In a brief 15-minute demo, he built a real-time Twitter clone without using a heavy JS framework like React, Angular, or Vue. He proved that developers could remain in the Back-End while maintaining high productivity and performance.
This success sparked similar implementations across various other programming languages.
"You can return to the Back-End without sacrificing the interactive experience of the Front-End."
The Role of JavaScript
It is a misconception that JavaScript is removed entirely. It is still present, but its responsibility shifts:
- Not for rendering: It doesn't build the UI.
- For communication: It manages the WebSocket connection.
- For placement: It inserts the received HTML into the DOM.
- For polish: It handles animations and basic event listeners.
How It Works: The Technical Shift
In a traditional setup, the browser requests data, receives JSON, and then executes logic to render the view.
With HTML over WebSockets, the request travels through a persistent pipe, and the response is already assembled HTML. Because the connection stays open, the server can "push" updates to the client without being asked.
The Simplified Flow
The Complete Lifecycle
Including the initial handshake and authentication, the process looks like this:
Why This Architecture Wins
The advantages are intrinsic to the design. We can represent the reduction in complexity as: By reducing both to , the overhead drops significantly.
Key Benefits:
- Unified Rendering: Only one engine is used, slashing architectural complexity.
- No API Overhead: The server talks directly to the client; no middleman JSON/GraphQL layer.
- Stateful Connections: Unlike
htmx(which is stateless), there is a dedicated process per client that remembers the current state. - Direct DB Access: The rendering logic lives right next to the database.
- True Real-Time: No polling required. The server pushes updates instantly.
- Native Broadcasting: Sending a message to all connected users (e.g., in a chat app) is built-in.
- Reduced Latency: By avoiding repeated TCP handshakes and bulky HTTP headers, the interaction feels snappier.
Conceptual Payload Example
Instead of a JSON object, the server sends a snippet like this:
<div id="user-count">
Current active users: <strong>42</strong>
</div>
Final Considerations: SEO and Security
SEO Performance: Since the initial page load is rendered on the server, it is fully indexable by search engines. However, keep in mind that crawlers generally do not trigger WebSocket updates.
- Rule of thumb: Ensure all critical content is present in the first HTML response.
Security: This method is inherently safer against injection attacks. Because the server handles the rendering and escapes the HTML before it ever enters the WebSocket channel, malicious scripts are transmitted as inert text rather than executable code.
![]()
Additional Resources & Credits:
![]()
:quality(85)/https://andros.dev/static/img/components/license/by-nc-nd.png)
