htmx Web Socket extension

The Web Sockets extension enables easy, bi-directional communication with Web Sockets servers directly from HTML. This replaces the experimental hx-ws attribute built into previous versions of htmx. For help migrating from older versions, see the Migrating guide at the bottom of this page.

Use the following attributes to configure how WebSockets behave:

Install


<script src="https://unpkg.com/htmx-ext-ws@2.0.1/ws.js"></script>

Usage


<div hx-ext="ws" ws-connect="/chatroom">
    <div id="notifications"></div>
    <div id="chat_room">
        ...
    </div>
    <form id="form" ws-send>
        <input name="chat_message">
    </form>
</div>

Configuration

WebSockets extension support two configuration options:

Receiving Messages from a WebSocket

The example above establishes a WebSocket to the /chatroom end point. Content that is sent down from the websocket will be parsed as HTML and swapped in by the id property, using the same logic as Out of Band Swaps.

As such, if you want to change the swapping method (e.g., append content at the end of an element or delegate swapping to an extension), you need to specify that in the message body, sent by the server.

<!-- will be interpreted as hx-swap-oob="true" by default -->
<form id="form">
    ...
</form>
<!-- will be appended to #notifications div -->
<div id="notifications" hx-swap-oob="beforeend">
    New message received
</div>
<!-- will be swapped using an extension -->
<div id="chat_room" hx-swap-oob="morphdom">
    ....
</div>

Sending Messages to a WebSocket

In the example above, the form uses the ws-send attribute to indicate that when it is submitted, the form values should be serialized as JSON and send to the nearest enclosing WebSocket, in this case the /chatroom endpoint.

The serialized values will include a field, HEADERS, that includes the headers normally submitted with an htmx request.

Automatic Reconnection

If the WebSocket is closed unexpectedly, due to Abnormal Closure, Service Restart or Try Again Later, this extension will attempt to reconnect until the connection is reestablished.

By default, the extension uses a full-jitter exponential-backoff algorithm that chooses a randomized retry delay that grows exponentially over time. You can use a different algorithm by writing it into htmx.config.wsReconnectDelay. This function takes a single parameter, the number of retries, and returns the time (in milliseconds) to wait before trying again.

// example reconnect delay that you shouldn't use because
// it's not as good as the algorithm that's already in place
htmx.config.wsReconnectDelay = function (retryCount) {
    return retryCount * 1000 // return value in milliseconds
}

The extension also implements a simple queuing mechanism that keeps messages in memory when the socket is not in OPEN state and sends them once the connection is restored.

Events

WebSockets extensions exposes a set of events that allow you to observe and customize its behavior.

Event - htmx:wsConnecting

This event is triggered when a connection to a WebSocket endpoint is being attempted.

Details

Event - htmx:wsOpen

This event is triggered when a connection to a WebSocket endpoint has been established.

Details

Event - htmx:wsClose

This event is triggered when a connection to a WebSocket endpoint has been closed normally. You can check if the event was caused by an error by inspecting detail.event property.

Details

Event - htmx:wsError

This event is triggered when onerror event on a socket is raised.

Details

Event - htmx:wsBeforeMessage

This event is triggered when a message has just been received by a socket, similar to htmx:beforeOnLoad. This event fires before any processing occurs.

If the event is cancelled, no further processing will occur.

Event - htmx:wsAfterMessage

This event is triggered when a message has been completely processed by htmx and all changes have been settled, similar to htmx:afterOnLoad.

Cancelling this event has no effect.

Event - htmx:wsConfigSend

This event is triggered when preparing to send a message from ws-send element. Similarly to htmx:configRequest, it allows you to modify the message before sending.

If the event is cancelled, no further processing will occur and no messages will be sent.

Details

Event - htmx:wsBeforeSend

This event is triggered just before sending a message. This includes messages from the queue. Message can not be modified at this point.

If the event is cancelled, the message will be discarded from the queue and not sent.

Details

Event - htmx:wsAfterSend

This event is triggered just after sending a message. This includes messages from the queue.

Cancelling the event has no effect.

Details

Socket wrapper

You may notice that all events expose detail.socketWrapper property. This wrapper holds the socket object itself and the message queue. It also encapsulates reconnection algorithm. It exposes a few members:

This wrapper can be used in your event handlers to monitor and manipulate the queue (e.g., you can reset the queue when reconnecting), and to send additional messages (e.g., if you want to send data in batches). The fromElt parameter is optional and, when specified, will trigger corresponding websocket events from specified element, namely htmx:wsBeforeSend and htmx:wsAfterSend events when sending your messages.

Testing with the Demo Server

Htmx includes a demo WebSockets server written in Node.js that will help you to see WebSockets in action, and begin bootstrapping your own WebSockets code. It is located in the /test/ws-sse folder of the htmx-extensions repository. Look at /test/ws-sse/README.md for instructions on running and using the test server.

Migrating from Previous Versions

Previous versions of htmx used a built-in tag hx-ws to implement WebSockets. This code has been migrated into an extension instead. Here are the steps you need to take to migrate to this version:

Old AttributeNew AttributeComments
hx-ws=""hx-ext="ws"Use the hx-ext="ws" attribute to install the WebSockets extension into any HTML element.
hx-ws="connect:<url>"ws-connect="<url>"Add a new attribute ws-connect to the tag that defines the extension to specify the URL of the WebSockets server you’re using.
hx-ws="send"ws-send=""Add a new attribute ws-send to mark any child forms that should send data to your WebSocket server