The Server Sent Events
extension connects to
an EventSource directly
from HTML. It manages the connections to your web server, listens for server events, and then swaps their contents into
your htmx webpage in real-time.
SSE is a lightweight alternative to WebSockets that works over existing HTTP connections, so it is easy to use through proxy servers and firewalls. Remember, SSE is a uni-directional service, so you cannot send any messages to an SSE server once the connection has been established. If you need bi-directional communication, then you should consider using WebSockets instead.
This extension replaces the experimental hx-sse
attribute built into previous versions of htmx. For help migrating
from older versions, see the migration guide at the bottom of this page.
Use the following attributes to configure how SSE connections behave:
sse-connect="<url>"
- The URL of the SSE server.sse-swap="<message-name>"
- The name of the message to swap into the DOM.hx-trigger="sse:<message-name>"
- SSE messages can also trigger HTTP callbacks using
the hx-trigger
attribute.sse-close=<message-name>
- To close the EventStream gracefully when that message is received. This might be helpful
if you want to send information to a client that will eventually stop.
<script src="https://unpkg.com/htmx-ext-sse@2.2.2/sse.js"></script>
<div hx-ext="sse" sse-connect="/chatroom" sse-swap="message">
Contents of this box will be updated in real time
with every SSE message received from the chatroom.
</div>
To connect to an SSE server, use the hx-ext="sse"
attribute to install the extension on that HTML element, then
add sse-connect="<url>"
to the element to make the connection.
When designing your server application, remember that SSE works just like any HTTP request. Although you cannot send any
messages to the server after you have established a connection, you can send parameters to the server along with your
request. So, instead of making an SSE connection to your server at https://my-server/chat-updates
you can also connect
to https://my-server/chat-updates?friends=true&format=detailed
. This allows your server to customize its responses to
what your client needs.
SSE messages consist of an event name and a data packet. No other metadata is allowed in the message. Here is an example:
event: EventName
data: <div>Content to swap into your HTML page.</div>
We’ll use the sse-swap
attribute to listen for this event and swap its contents into our webpage.
<div hx-ext="sse" sse-connect="/event-source" sse-swap="EventName"></div>
Notice that the name EventName
from the server’s message must match the value in the sse-swap
attribute. Your server
can use as many different event names as necessary, but be careful: browsers can only listen for events that have been
explicitly named. So, if your server sends an event named ChatroomUpdate
but your browser is only listening for events
named ChatUpdate
then the extra event will be discarded.
SSE messages can also be sent without any event name. In this case, the browser uses the default name message
in its
place. The same rules specified above still apply. If your server sends an unnamed message, then you must listen for it
by including sse-swap="message"
. There is no option for using a catch-all name. Here’s how this looks:
data: <div>Content to swap into your HTML page.</div>
<div hx-ext="sse" sse-connect="/event-source" sse-swap="message"></div>
You can also listen to multiple events (named or unnamed) from a single EventSource. Listeners must be either 1) the
same element that contains the hx-ext
and sse-connect
attributes, or 2) child elements of the element containing
the hx-ext
and sse-connect
attributes.
Multiple events in the same element
<div hx-ext="sse" sse-connect="/server-url" sse-swap="event1,event2"></div>
Multiple events in different elements (from the same source).
<div hx-ext="sse" sse-connect="/server-url">
<div sse-swap="event1"></div>
<div sse-swap="event2"></div>
</div>
When a connection for server sent events has been established, child elements can listen for these events by using the
special hx-trigger
syntax sse:<event_name>
. This, when combined with
an hx-get
or similar will trigger the element to make a request.
Here is an example:
<div hx-ext="sse" sse-connect="/event_stream">
<div hx-get="/chatroom" hx-trigger="sse:chatter">
...
</div>
</div>
This example establishes an SSE connection to the event_stream
end point which then triggers
a GET
to the /chatroom
url whenever the chatter
event is seen.
If the SSE Event Stream is closed unexpectedly, browsers are supposed to attempt to reconnect automatically. However, in rare situations this does not work and your browser can be left hanging. This extension adds its own reconnection logic (using an exponential-backoff algorithm) on top of the browser’s automatic reconnection, so that your SSE streams will always be as reliable as possible.
Htmx includes a demo SSE server written in Node.js that will help you to see SSE in action, and begin bootstrapping your
own SSE 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.
Previous versions of htmx used a built-in tag hx-sse
to implement Server Sent Events. This code has been migrated into
an extension instead. Here are the steps you need to take to migrate to this version:
Old Attribute | New Attribute | Comments |
---|---|---|
hx-sse="" | hx-ext="sse" | Use the hx-ext="sse" attribute to install the SSE extension into any HTML element. |
hx-sse="connect:<url>" | sse-connect="<url>" | Add a new attribute sse-connect to the tag that specifies the URL of the Event Stream. This attribute must be in the same tag as the hx-ext attribute. |
hx-sse="swap:<EventName>" | sse-swap="<EventName>" | Add a new attribute sse-swap to any elements that will be swapped in via the SSE extension. This attribute must be placed on or inside of the tag containing the hx-ext attribute. |
hx-trigger="sse:<EventName>" | NO CHANGE | any hx-trigger attributes do not need to change. The extension will identify these attributes and add listeners for any events prefixed with sse: |
This extension dispatches several events. You can listen for these events like so:
document.body.addEventListener('htmx:sseBeforeMessage', function (e) {
// do something before the event data is swapped in
})
Each event object has a detail
field that contains details of the event.
htmx:sseOpen
This event is dispatched when an SSE connection has been successfully established.
detail.elt
- The element on which the SSE connection was setup. This is the element which has the sse-connect
attribute.detail.source
- The EventSource object.htmx:sseError
This event is dispatched when an SSE connection could not be established.
detail.error
- The error that occurred while creating
an EventSource.detail.source
- The EventSource.htmx:sseBeforeMessage
This event is dispatched just before the SSE event data is swapped into the DOM. If you don’t want to swap
call preventDefault()
on the event. Additionally the detail
field is
a MessageEvent - this is the event created
by EventSource when it receives an SSE message.
detail.elt
- The swap target.htmx:sseMessage
This event is dispatched after the SSE event data has been swapped into the DOM. The detail
field is
a MessageEvent - this is the event created
by EventSource when it receives an SSE message.
htmx:sseClose
This event is dispatched in three different closing scenario. To control for the scenario the user can control for the evt.detail.sseclose property.
document.body.addEventListener('htmx:sseClose', function (e) {
const reason = e.detail.type
switch (reason) {
case "nodeMissing":
// Parent node is missing and therefore connection was closed
...
case "nodeReplaced":
// Parent node replacement caused closing of connection
...
case "message":
// connection was closed due to reception of message sse-close
...
}
})
detail.elt
- The swap target.