Back

UX em Tempo Real com a Extensão SSE do htmx

UX em Tempo Real com a Extensão SSE do htmx

A maioria das aplicações web precisa de atualizações ao vivo em algum momento — um badge de notificação, uma barra de progresso, um dashboard que atualiza sem polling. A resposta usual são WebSockets ou um framework SPA completo. Mas se você já está usando htmx, existe um caminho mais simples: a extensão SSE do htmx, que conecta eventos enviados pelo servidor diretamente ao seu HTML com quase nenhum JavaScript.

Pontos-Chave

  • Server-Sent Events (SSE) fornecem streaming unidirecional, do servidor para o cliente, sobre HTTP padrão — ideal para notificações, dashboards e feeds ao vivo.
  • A extensão SSE do htmx é um pacote separado (htmx-ext-sse) que conecta streams SSE ao seu HTML usando atributos declarativos, sem necessidade de JavaScript personalizado.
  • Três atributos principais — sse-connect, sse-swap e hx-trigger="sse:<event>" — cobrem a maioria dos padrões de UX em tempo real.
  • SSE é mais simples de implementar do que WebSockets e elimina as requisições desperdiçadas do polling, embora suporte apenas comunicação do servidor para o cliente.

O Que São Server-Sent Events na Prática

Server-Sent Events (SSE) é um protocolo nativo do navegador para streaming unidirecional, do servidor para o cliente, sobre uma conexão HTTP padrão. O servidor mantém a conexão aberta e envia eventos de texto sempre que tem algo a comunicar. O navegador os recebe através da API EventSource.

O formato no protocolo é texto simples:

event: priceUpdate
data: <li>BTC — $62,400</li>

Cada evento tem um nome opcional e um payload data. Múltiplas linhas data: são concatenadas. Os eventos são separados por uma linha em branco.

Como SSE funciona sobre HTTP, ele opera através de proxies e firewalls sem configuração especial. Suporta reconexão automática nativamente. A contrapartida é a direcionalidade: uma vez que a conexão está aberta, o cliente não pode enviar mensagens de volta. Para notificações, dashboards, progresso de tarefas e feeds ao vivo, isso é perfeitamente adequado. Para chat ou edição colaborativa, você precisaria de WebSockets.

Instalando a Extensão SSE do htmx

O suporte a SSE não está embutido no núcleo do htmx. Ele reside no pacote separado htmx-ext-sse. Carregue ambos os scripts e ative a extensão em um elemento container:

<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 builds baseados em npm, instale com npm install htmx-ext-sse e importe tanto htmx.org quanto htmx-ext-sse no seu arquivo de entrada.

Nota: O antigo atributo hx-sse de versões anteriores do htmx está obsoleto. Use hx-ext="sse" com a extensão dedicada.

Atributos Principais para Atualizações em Streaming com htmx

Três atributos cobrem a maioria dos padrões de UX em tempo real:

AtributoPropósito
sse-connect="<url>"Abre a conexão EventSource
sse-swap="<event-name>"Substitui o HTML recebido no elemento
hx-trigger="sse:<event-name>"Dispara uma requisição htmx quando o evento chega

Um feed ao vivo que substitui seu próprio conteúdo a cada push:

<div hx-ext="sse" sse-connect="/feed" sse-swap="message">
  Carregando…
</div>

O servidor envia um evento com data: <p>Novo item</p> seguido de uma linha em branco, e o htmx substitui o conteúdo da div — nenhum JavaScript necessário.

Lidando com Múltiplos Eventos e Disparando Requisições

Um único sse-connect pode alimentar vários elementos filhos, cada um ouvindo um nome de evento diferente:

<div hx-ext="sse" sse-connect="/stream">
  <div sse-swap="statsUpdate"></div>
  <div sse-swap="alertBanner"></div>
</div>

Você também pode usar eventos SSE para disparar requisições HTTP subsequentes em vez de trocar conteúdo diretamente. Isso é útil quando o evento sinaliza que dados atualizados estão disponíveis, mas você quer que o htmx busque o fragmento renderizado completo:

<div hx-ext="sse" sse-connect="/events">
  <div hx-get="/notifications" hx-trigger="sse:newNotification">
    <!-- atualizado a cada evento SSE -->
  </div>
</div>

Para fechar um stream graciosamente quando o servidor sinaliza conclusão, adicione sse-close="done" — a conexão fecha quando um evento chamado done chega.

Quando SSE Supera Polling ou WebSockets

  • vs. polling: SSE elimina requisições desperdiçadas. O servidor envia apenas quando algo muda.
  • vs. WebSockets: SSE é mais simples de implementar, funciona sobre HTTP/1.1 e HTTP/2, e não precisa de infraestrutura especial no servidor. Use WebSockets apenas quando precisar de comunicação bidirecional.

Uma nota prática: navegadores HTTP/1.1 limitam conexões por domínio a seis. Se usuários abrem múltiplas abas, as conexões SSE competem por esse limite. Servir sobre HTTP/2 amplamente evita essa limitação ao multiplexar múltiplos streams sobre uma única conexão.

Conclusão

A extensão SSE do htmx permite adicionar UI genuína em tempo real com HTML-over-the-wire — dashboards ao vivo, indicadores de progresso, streams de notificação — com alguns atributos HTML e um endpoint no servidor que sabe manter uma conexão aberta. Sem biblioteca de gerenciamento de estado, sem roteamento client-side, sem pipeline de build necessário. Se seu servidor pode fazer streaming de texto, sua UI pode estar ao vivo.

Perguntas Frequentes

Não. Server-Sent Events são estritamente unidirecionais, do servidor para o cliente. Se você precisa enviar dados de volta, combine seu stream SSE com requisições htmx padrão usando hx-post ou hx-put. Para comunicação totalmente bidirecional, como chat em tempo real, WebSockets são a melhor escolha.

A API EventSource nativa do navegador automaticamente tenta reconectar após um breve atraso. O servidor pode controlar o intervalo de retry incluindo um campo retry no stream de eventos. A extensão SSE do htmx herda esse comportamento de reconexão sem nenhuma configuração extra da sua parte.

Sim, e HTTP/2 é realmente recomendado. Sob HTTP/1.1, navegadores limitam conexões simultâneas por domínio a cerca de seis, então múltiplas abas com streams SSE abertos podem esgotar esse limite. HTTP/2 multiplexa streams sobre uma única conexão, efetivamente removendo o limite.

Envie um evento nomeado que corresponda ao valor do atributo sse-close no seu elemento container. Por exemplo, se você definir sse-close igual a done, enviar um evento com o nome done fará com que a extensão feche a conexão EventSource de forma limpa no lado do 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.

OpenReplay