HTMX 4.0 Acabou de Sair: Tudo que Muda no Frontend Sem JavaScript
Enquanto metade da comunidade frontend ainda discute se deveria usar React, Vue ou Svelte, o HTMX simplesmente lançou a versão 4.0 e jogou mais lenha nessa fogueira. A biblioteca de 14KB que promete devolver o HTML ao centro do desenvolvimento web acaba de ganhar streaming nativo, morph swaps embutidos e uma tag nova que faz o out-of-band swap parecer coisa do passado.
Se você nunca ouviu falar de HTMX, a premissa é simples: em vez de escrever JavaScript para fazer requisições AJAX e manipular o DOM, você coloca atributos HTML nos seus elementos e o HTMX cuida do resto. Clicou num botão? Ele faz um POST, pega o HTML que o servidor devolveu e enfia no lugar certo da página. Sem virtual DOM, sem state management, sem bundle de 2MB.
A versão 4.0, batizada internamente de “The Fetchening”, traz mudanças que vão desde a troca do motor interno (adeus XMLHttpRequest, olá Fetch API) até uma reformulação completa de como atributos são herdados no DOM. Eu já passei as últimas horas lendo o changelog e testando, então vou poupar você do trabalho.
O que é HTMX (para quem chegou agora)
HTMX é uma biblioteca JavaScript criada por Carson Gross que extende o HTML com atributos como hx-get, hx-post, hx-swap e hx-target. A ideia central é que o servidor deveria devolver HTML, não JSON, e que o navegador deveria ser tratado como um cliente hypermedia, não como uma plataforma de execução de aplicações JavaScript.
Na prática, isso significa que você pode construir aplicações web interativas escrevendo basicamente zero JavaScript. Um formulário que salva sem reload? Um botão que carrega mais itens numa lista infinita? Uma busca com autocomplete? Tudo isso vira questão de adicionar dois ou três atributos no HTML e deixar o servidor responder com fragmentos HTML.
<!-- Busca com HTMX: zero JavaScript -->
<input type="search"
name="q"
hx-get="/busca"
hx-trigger="keyup changed delay:300ms"
hx-target="#resultados"
hx-swap="innerHTML">
<div id="resultados"></div>
O HTMX ganhou tração absurda nos últimos anos. A comunidade Python/Django adotou com força, o ecossistema Go abraçou, e até desenvolvedores Rails que já tinham Hotwire começaram a olhar com interesse. Com 40 mil+ estrelas no GitHub, virou impossível ignorar.
A Grande Troca: XMLHttpRequest Sai, Fetch API Entra
A mudança mais profunda do HTMX 4.0 acontece por baixo do capô. Desde a primeira versão, o HTMX usava XMLHttpRequest (XHR) para fazer requisições HTTP. Funcionava bem, todo mundo conhecia, mas é uma API de 2006. Literalmente. O XHR foi padronizado quando o jQuery ainda tinha dois anos de idade.
A versão 4.0 migrou tudo para a Fetch API. Para a maioria dos desenvolvedores, essa mudança é transparente: seus hx-get e hx-post continuam funcionando exatamente igual. Mas os efeitos colaterais são enormes.
O primeiro e mais impactante: streaming nativo de HTML. Com a Fetch API, o HTMX agora pode processar respostas via ReadableStream. Isso significa que o servidor pode começar a enviar HTML e o navegador já vai renderizando conforme os pedaços chegam, sem esperar a resposta completa.
# Exemplo com FastAPI: streaming de fragmentos HTML
from fastapi.responses import StreamingResponse
async def gerar_cards():
for item in buscar_itens():
yield f'''
<div class="card" style="view-transition-name: card-{item.id}">
<h3>{item.titulo}</h3>
<p>{item.resumo}</p>
</div>
'''
@app.get("/cards")
async def listar_cards():
return StreamingResponse(gerar_cards(), media_type="text/html")
Para quem já trabalhou com React Server Components, isso vai soar familiar. A diferença é que o HTMX faz isso com 14KB, sem build step, sem bundler, sem node_modules com 800MB.
O segundo efeito: compatibilidade melhor com Service Workers, Content Security Policy mais restritiva, e suporte a AbortController para cancelar requisições em andamento.
Morph Swaps: Agora É Nativo
Se você já usou o HTMX 2.x, provavelmente conhece (ou deveria conhecer) a extensão Idiomorph. Era uma extensão separada que, em vez de simplesmente substituir um pedaço do DOM por HTML novo, fazia um “diff” inteligente: comparava o HTML antigo com o novo e atualizava só o que mudou.
Por que isso importa? Porque o swap padrão do HTMX (innerHTML, outerHTML) destrói e recria elementos. Se o usuário estava digitando num input, perdeu o foco. Se tinha um vídeo tocando dentro daquele trecho, reiniciou. Se tinha um tooltip aberto, fechou.
O morph swap resolve tudo isso. Ele preserva foco, scroll position, estado de inputs e qualquer outro estado do DOM que não mudou.
No HTMX 4.0, o Idiomorph foi incorporado ao core. Agora você usa morphInner e morphOuter como qualquer outro tipo de swap, sem instalar extensão:
<!-- Atualiza a lista preservando estado dos elementos -->
<div hx-get="/tarefas"
hx-trigger="every 5s"
hx-swap="morphInner">
<!-- Lista de tarefas atualiza sem perder foco/scroll -->
</div>
Essa mudança sozinha já justificaria o upgrade para muita gente. A complexidade que o morph swap economiza em código JavaScript defensivo (salvar foco, restaurar scroll, re-inicializar componentes) é absurda.
A Tag : O Fim do Sofrimento com OOB Swaps
Se existe uma feature do HTMX 2.x que gerava mais confusão do que ajudava, era o out-of-band swap (OOB). A ideia era boa: quando o servidor responde a uma requisição, além de atualizar o alvo principal, ele pode mandar pedaços extras de HTML marcados com hx-swap-oob="true" que seriam inseridos em outros lugares da página.
Na prática, era um pesadelo de debugging. O HTML vinha misturado na resposta, a ordem importava, e quando algo dava errado, boa sorte tentando entender por que aquele pedaço do DOM não atualizou.
O HTMX 4.0 introduz a tag , que é uma solução muito mais limpa para o mesmo problema:
<!-- Resposta do servidor com múltiplos targets -->
<!-- Atualiza a lista de mensagens -->
<hx-partial hx-target="#messages" hx-swap="beforeend">
<div class="message">Nova mensagem do servidor!</div>
</hx-partial>
<!-- Atualiza o contador no header -->
<hx-partial hx-target="#msg-count" hx-swap="innerHTML">
<span>42</span>
</hx-partial>
<!-- Atualiza a sidebar -->
<hx-partial hx-target="#sidebar-status" hx-swap="outerHTML">
<div id="sidebar-status" class="online">Conectado</div>
</hx-partial>
Cada especifica seu próprio target e tipo de swap. O servidor pode devolver quantos partials quiser numa única resposta, e cada um vai pro lugar certo. Sem mágica, sem atributos ocultos, sem ordem específica.
Comparado com o OOB do HTMX 2.x, é como trocar um Fusca 78 por um carro automático. Faz a mesma coisa, só que sem te fazer sofrer.
Herança de Atributos: A Mudança que Vai Quebrar Seu Código
Aqui é onde dói. Se você tem um projeto HTMX 2.x em produção, essa é a mudança que vai exigir mais trabalho na migração.
No HTMX 2.x, atributos como hx-target, hx-swap, hx-confirm e hx-headers eram herdados automaticamente pelos elementos filhos. Você colocava hx-confirm="Tem certeza?" num <div> e todos os botões dentro dele herdavam essa confirmação. Parecia conveniente.
O problema? Era um inferno de debugging quando a herança causava comportamentos inesperados. Um hx-target definido lá em cima na árvore DOM afetava um botão que você não lembrava que era filho daquele elemento. Tokens CSRF definidos com hx-headers num container vazavam para requisições que não deveriam tê-los.
O HTMX 4.0 inverte o padrão: nenhum atributo é herdado por padrão. Se você quer herança, precisa declarar explicitamente com o sufixo :inherited:
<!-- HTMX 2.x (herança implícita) -->
<div hx-confirm="Tem certeza?" hx-headers='{"X-CSRF-Token": "abc123"}'>
<button hx-delete="/item/1">Deletar</button> <!-- herdava tudo -->
<button hx-post="/item/1/archive">Arquivar</button> <!-- herdava tudo -->
</div>
<!-- HTMX 4.0 (herança explícita) -->
<div hx-confirm:inherited="Tem certeza?"
hx-headers:inherited='{"X-CSRF-Token": "abc123"}'>
<button hx-delete="/item/1">Deletar</button> <!-- herda porque é :inherited -->
<button hx-post="/item/1/archive">Arquivar</button> <!-- herda porque é :inherited -->
</div>
O hx-disinherit que existia no 2.x foi removido completamente. Não precisa mais, já que nada herda por padrão.
Parece chato? É. Mas depois de migrar, seu código fica muito mais previsível. Cada elemento faz exatamente o que você declarou nele, sem surpresas herdadas de ancestrais distantes no DOM.
Eventos Reformulados: Mais Limpos, Mais Previsíveis
O sistema de eventos do HTMX 2.x era funcional, mas a nomenclatura era inconsistente. Tinha htmx:beforeRequest (camelCase), htmx:afterSwap (camelCase), e uma porção de eventos específicos para XHR que nem fazia sentido manter com a migração para Fetch.
O HTMX 4.0 padroniza tudo no formato htmx:phase:action:
| HTMX 2.x | HTMX 4.0 | |
|---|---|---|
| ———– | ———– | |
htmx:beforeRequest |
htmx:before:request |
|
htmx:afterRequest |
htmx:after:request |
|
htmx:beforeSwap |
htmx:before:swap |
|
htmx:afterSwap |
htmx:after:swap |
|
htmx:configRequest |
htmx:config:request |
|
htmx:responseError |
htmx:response:error |
Eventos de validação (htmx:validation:<em>) e de XHR (htmx:xhr:</em>) foram removidos. A maioria dos eventos de erro agora converge para htmx:error, que é muito mais fácil de lidar:
// HTMX 4.0: handler unificado de erro
document.addEventListener('htmx:error', (event) => {
console.error('Algo deu errado:', event.detail);
mostrarNotificacao('Erro na requisição. Tente novamente.');
});
Respostas de Erro Agora São Renderizadas
Essa é sutil, mas muda tudo na experiência do usuário. No HTMX 2.x, quando o servidor respondia com um código 4xx ou 5xx, o HTMX basicamente ignorava o HTML da resposta. Você recebia o evento de erro, mas o conteúdo sumia no limbo.
No HTMX 4.0, respostas de erro são renderizadas por padrão. Se seu servidor devolver um 422 (Unprocessable Entity) com HTML mostrando os erros de validação, esse HTML vai ser inserido no target normalmente.
Além disso, o novo atributo hx-status permite rotear respostas por código HTTP:
<form hx-post="/cadastro"
hx-target="#resultado"
hx-status:422="#erros-validacao"
hx-status:5xx="#erro-servidor">
<!-- campos do formulário -->
<button type="submit">Cadastrar</button>
</form>
<div id="resultado"></div>
<div id="erros-validacao"></div>
<div id="erro-servidor"></div>
Um 200 vai pro #resultado. Um 422 vai pro #erros-validacao. Qualquer 5xx vai pro #erro-servidor. Sem JavaScript, sem if/else, sem try/catch.
View Transitions Nativas
O HTMX 4.0 integra nativamente com a View Transitions API do navegador. Isso significa transições animadas entre estados da página (fade, slide, morph) com CSS puro:
<a hx-get="/pagina-2"
hx-target="body"
hx-swap="innerHTML transition:true">
Ir para página 2
</a>
::view-transition-old(root) {
animation: fade-out 0.3s ease-in;
}
::view-transition-new(root) {
animation: fade-in 0.3s ease-out;
}
@keyframes fade-out {
from { opacity: 1; }
to { opacity: 0; }
}
@keyframes fade-in {
from { opacity: 0; }
to { opacity: 1; }
}
Transições suaves entre páginas que antes exigiam bibliotecas como Barba.js ou frameworks inteiros agora são três linhas de atributo HTML e um pouco de CSS.
O Fim do Cache no localStorage
O HTMX 2.x tinha um sistema de cache de histórico que salvava páginas no localStorage. A ideia era que, ao clicar “voltar” no navegador, a página anterior aparecesse instantaneamente do cache em vez de fazer uma nova requisição.
Na teoria, brilhante. Na prática, um campo minado. Scripts de terceiros modificavam o DOM (analytics, chat widgets, A/B testing), e essas modificações eram salvas junto. Quando o usuário voltava, a página restaurada vinha com mutações fantasma que causavam bugs impossíveis de reproduzir.
O HTMX 4.0 simplesmente abandonou esse cache. Agora, voltar no navegador re-busca a página do servidor. É mais lento? Talvez uns milissegundos. Mas é previsível. E para quem realmente precisa do cache, existe a extensão hx-history-cache que usa sessionStorage (que limpa quando fecha a aba).
Novas Extensões que Valem a Pena
O ecossistema de extensões também cresceu:
| Extensão | O que faz | |
|---|---|---|
| ———- | ———– | |
hx-preload |
Pré-carrega conteúdo quando o usuário passa o mouse sobre um link | |
hx-download |
Download nativo de arquivos via HTMX | |
hx-alpine-compat |
Integração mais suave com Alpine.js | |
hx-live |
Scripting reativo inspirado em Alpine + jQuery | |
hx-sse / hx-ws |
Server-Sent Events e WebSocket atualizados para Fetch | |
hx-multipart |
Upload de arquivos multipart |
O hx-preload sozinho é ouro: coloque num link e o HTMX vai buscar o conteúdo quando o usuário passar o mouse. Quando clicar, a página já está pronta. Percepção de velocidade instantânea, sem nenhuma complexidade.
E tem o htmax.js, um bundle que empacota o HTMX core com as extensões mais populares num único arquivo. Para quem não quer ficar gerenciando imports, é plug and play.
Como Migrar do HTMX 2.x para 4.0
O time do HTMX criou uma ferramenta de linha de comando que escaneia seus templates e aponta o que precisa mudar:
npx htmx.org@4.0.0 upgrade-check -- ./templates
A ferramenta identifica:
- Atributos que precisam do sufixo
:inherited - Atributos renomeados (
hx-disablevirouhx-ignore) - Atributos removidos (
hx-vars,hx-prompt,hx-disinherit) - Event listeners com nomes antigos
- Chamadas de API depreciadas (
htmx.addClass()virouclassList.add()nativo)
Boa notícia: o HTMX 2.x vai continuar recebendo patches de segurança por tempo indeterminado. No npm, a tag latest ainda aponta pro 2.x, e o 4.0 está como next. Então ninguém que faz npm install htmx.org sem especificar versão vai ter surpresas.
A recomendação do próprio Carson Gross é: projetos novos, vai direto no 4.0. Projetos existentes, migre no seu ritmo. Não tem pressa.
HTMX 4.0 vs React/Vue/Svelte: Quando Usar Cada Um
Essa é a pergunta que não quer calar, e a resposta honesta é: depende do tipo de interatividade que sua aplicação precisa.
O HTMX brilha em:
- Sites com conteúdo dinâmico mas estado simples (blogs, dashboards, e-commerce, CRMs)
- Aplicações server-rendered que precisam de interatividade sem SPA
- Projetos onde a equipe é forte em backend mas não quer virar “full-stack JavaScript”
- Prototipagem rápida
Frameworks JavaScript SPA ainda vencem quando:
- A aplicação é altamente interativa (Google Docs, Figma, jogos)
- Você precisa de estado complexo no client-side com sincronização em tempo real
- A experiência offline é requisito crítico
O ponto que muita gente erra é achar que precisa escolher um ou outro. Você pode ter 90% da sua aplicação em HTMX e aquela uma tela complexa de drag-and-drop em React. As duas abordagens coexistem perfeitamente.
O Bundle que Pesa Menos que um Favicon
Sabe aquele favicon .ico que todo site tem? Em média, ele tem uns 15 a 30KB. O HTMX 4.0 inteiro, minificado e gzipado, tem 14KB. Com morph swaps incluídos.
Para colocar em perspectiva:
| Biblioteca/Framework | Tamanho (gzip) | |
|---|---|---|
| ——————— | —————- | |
| HTMX 4.0 (com morph) | ~14KB | |
| Alpine.js 3.x | ~17KB | |
| jQuery 3.7 | ~30KB | |
| Vue 3 (runtime) | ~45KB | |
| React + ReactDOM | ~44KB | |
| Next.js (runtime mínimo) | ~80KB+ |
Isso antes de contar seu código. Um projeto Next.js médio manda 200 a 500KB de JavaScript pro navegador. Um projeto HTMX manda 14KB. A diferença de performance no carregamento inicial, especialmente em dispositivos móveis e redes lentas, é brutal.
Quem Está Usando HTMX em Produção
A lista é maior do que muita gente imagina. Segundo a própria documentação do HTMX, empresas como a Contexte (mídia), a Odoo (ERP open source), e centenas de startups usam HTMX como stack principal de frontend.
No ecossistema Django, o HTMX praticamente virou padrão. Pacotes como django-htmx têm milhares de downloads por dia. O mesmo acontece com Go (usando Templ + HTMX), Elixir/Phoenix (que já tinha LiveView, mas ganhou opção HTMX), e Rust com Axum ou Actix.
A comunidade também é peculiar: é um dos poucos projetos de tech que tem seu próprio zine de humor e memes. O criador, Carson Gross, tem um senso de humor ácido que transparece na documentação, nos essays e até nos nomes dos releases (“The Fetchening” é referência a um meme de fetch no JavaScript).
Instalando e Testando Agora
Se você quer testar o HTMX 4.0 agora mesmo, são literalmente duas linhas:
<!DOCTYPE html>
<html>
<head>
<script src="https://unpkg.com/htmx.org@4.0.0/dist/htmx.min.js"></script>
</head>
<body>
<button hx-get="https://httpbin.org/html"
hx-target="#resultado"
hx-swap="innerHTML">
Carregar HTML
</button>
<div id="resultado"></div>
</body>
</html>
Salve num arquivo .html, abra no navegador, clique no botão. Pronto, você está usando HTMX. Sem npm, sem webpack, sem vite, sem turbopack, sem node_modules. Um arquivo HTML e um CDN.
Para projetos mais sérios, instale via npm:
npm install htmx.org@4.0.0
Ou via CDN com integridade:
<script src="https://unpkg.com/htmx.org@4.0.0/dist/htmx.min.js"
integrity="sha384-..."
crossorigin="anonymous"></script>
O HTMX 4.0 acaba de sair hoje, está quente, e a comunidade já está migrando. Se você estava esperando um motivo para experimentar essa abordagem hypermedia de construir aplicações web, esse é o momento. A biblioteca nunca esteve tão madura, o ecossistema nunca esteve tão rico, e o JavaScript que você não vai precisar escrever nunca foi tão abundante.













