UX en Tiempo Real con la Extensión SSE de htmx
La mayoría de las aplicaciones web necesitan actualizaciones en vivo en algún momento: un indicador de notificaciones, una barra de progreso, un panel de control que se actualice sin polling. La respuesta habitual son WebSockets o un framework SPA completo. Pero si ya estás usando htmx, hay un camino más simple: la extensión SSE de htmx, que conecta eventos enviados por el servidor directamente en tu HTML con casi nada de JavaScript.
Puntos Clave
- Los Server-Sent Events (SSE) proporcionan transmisión unidireccional de servidor a cliente sobre HTTP estándar, ideal para notificaciones, paneles de control y feeds en vivo.
- La extensión SSE de htmx es un paquete separado (
htmx-ext-sse) que conecta flujos SSE a tu HTML usando atributos declarativos, sin necesidad de JavaScript personalizado. - Tres atributos principales —
sse-connect,sse-swapyhx-trigger="sse:<event>"— cubren la mayoría de los patrones de UX en tiempo real. - SSE es más simple de desplegar que WebSockets y elimina las peticiones desperdiciadas del polling, aunque solo soporta comunicación de servidor a cliente.
Qué Son Realmente los Server-Sent Events
Server-Sent Events (SSE) es un protocolo nativo del navegador para transmisión unidireccional de servidor a cliente sobre una conexión HTTP estándar. El servidor mantiene la conexión abierta y envía eventos de texto cuando tiene algo que comunicar. El navegador los recibe a través de la API EventSource.
El formato en el cable es texto plano:
event: priceUpdate
data: <li>BTC — $62,400</li>
Cada evento tiene un nombre opcional y una carga útil data. Múltiples líneas data: se concatenan. Los eventos se separan por una línea en blanco.
Debido a que SSE funciona sobre HTTP, trabaja a través de proxies y firewalls sin configuración especial. Soporta reconexión automática de forma nativa. El compromiso es la direccionalidad: una vez que la conexión está abierta, el cliente no puede enviar mensajes de vuelta. Para notificaciones, paneles de control, progreso de tareas y feeds en vivo, eso está perfectamente bien. Para chat o edición colaborativa, necesitarías WebSockets en su lugar.
Instalando la Extensión SSE de htmx
El soporte SSE no está integrado en el núcleo de htmx. Vive en el paquete separado htmx-ext-sse. Carga ambos scripts y activa la extensión en un elemento contenedor:
<head>
<script src="https://cdn.jsdelivr.net/npm/htmx.org@latest/dist/htmx.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/htmx-ext-sse@latest"></script>
</head>
<body hx-ext="sse">
Para compilaciones basadas en npm, instala con npm install htmx-ext-sse e importa tanto htmx.org como htmx-ext-sse en tu archivo de entrada.
Nota: El antiguo atributo
hx-ssede versiones anteriores de htmx está deprecado. Usahx-ext="sse"con la extensión dedicada en su lugar.
Atributos Principales para Actualizaciones en Streaming con htmx
Tres atributos cubren la mayoría de los patrones de UX en tiempo real:
| Atributo | Propósito |
|---|---|
sse-connect="<url>" | Abre la conexión EventSource |
sse-swap="<event-name>" | Intercambia el HTML entrante en el elemento |
hx-trigger="sse:<event-name>" | Dispara una petición htmx cuando llega el evento |
Un feed en vivo que reemplaza su propio contenido en cada envío:
<div hx-ext="sse" sse-connect="/feed" sse-swap="message">
Cargando…
</div>
El servidor envía un evento con data: <p>Nuevo elemento</p> seguido de una línea en blanco, y htmx reemplaza el contenido del div — sin JavaScript requerido.
Discover how at OpenReplay.com.
Manejando Múltiples Eventos y Disparando Peticiones
Un sse-connect puede alimentar varios elementos hijos, cada uno escuchando un nombre de evento diferente:
<div hx-ext="sse" sse-connect="/stream">
<div sse-swap="statsUpdate"></div>
<div sse-swap="alertBanner"></div>
</div>
También puedes usar eventos SSE para disparar peticiones HTTP de seguimiento en lugar de intercambiar contenido directamente. Esto es útil cuando el evento señala que hay datos frescos disponibles pero quieres que htmx obtenga el fragmento renderizado completo:
<div hx-ext="sse" sse-connect="/events">
<div hx-get="/notifications" hx-trigger="sse:newNotification">
<!-- actualizado en cada evento SSE -->
</div>
</div>
Para cerrar un flujo de manera elegante cuando el servidor señala la finalización, agrega sse-close="done" — la conexión se cierra cuando llega un evento llamado done.
Cuándo SSE Supera al Polling o WebSockets
- vs. polling: SSE elimina peticiones desperdiciadas. El servidor envía solo cuando algo cambia.
- vs. WebSockets: SSE es más simple de desplegar, funciona sobre HTTP/1.1 y HTTP/2, y no necesita infraestructura de servidor especial. Usa WebSockets solo cuando necesites comunicación bidireccional.
Una nota práctica: los navegadores con HTTP/1.1 limitan las conexiones por dominio a seis. Si los usuarios abren múltiples pestañas, las conexiones SSE compiten por ese límite. Servir sobre HTTP/2 evita en gran medida esta limitación al multiplexar múltiples flujos sobre una única conexión.
Conclusión
La extensión SSE de htmx te permite agregar una interfaz de usuario genuina en tiempo real con HTML-sobre-el-cable — paneles de control en vivo, indicadores de progreso, flujos de notificaciones — con unos pocos atributos HTML y un endpoint de servidor que sabe cómo mantener una conexión abierta. No se requiere librería de gestión de estado, ni enrutamiento del lado del cliente, ni pipeline de compilación. Si tu servidor puede transmitir texto, tu interfaz puede estar en vivo.
Preguntas Frecuentes
No. Los Server-Sent Events son estrictamente unidireccionales, de servidor a cliente. Si necesitas enviar datos de vuelta, combina tu flujo SSE con peticiones htmx estándar usando hx-post o hx-put. Para comunicación completamente bidireccional, como chat en tiempo real, WebSockets son la mejor opción.
La API EventSource integrada del navegador intenta automáticamente reconectarse después de un breve retraso. El servidor puede controlar el intervalo de reintento incluyendo un campo retry en el flujo de eventos. La extensión SSE de htmx hereda este comportamiento de reconexión sin ninguna configuración extra de tu parte.
Sí, y de hecho HTTP/2 es recomendado. Bajo HTTP/1.1, los navegadores limitan las conexiones simultáneas por dominio a aproximadamente seis, por lo que múltiples pestañas con flujos SSE abiertos pueden agotar ese límite. HTTP/2 multiplexa flujos sobre una única conexión, eliminando efectivamente el límite.
Envía un evento nombrado que coincida con el valor del atributo sse-close en tu elemento contenedor. Por ejemplo, si estableces sse-close igual a done, enviar un evento con el nombre done hará que la extensión cierre la conexión EventSource limpiamente en el lado del cliente.
Gain Debugging Superpowers
Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers. Check our GitHub repo and join the thousands of developers in our community.