htmx em 2026: Quando Você Não Precisa de React (E Quando Precisa Sim)
A comunidade frontend vem brigando sobre htmx vs React há dois anos, e a maioria dos argumentos erra o ponto. Não porque alguma tecnologia seja ruim, mas porque o debate coloca as duas como concorrentes resolvendo o mesmo problema. E não é o caso.
htmx passou de 47.000 estrelas no GitHub. React continua rodando em milhões de apps em produção. A pesquisa State of JS 2025 (publicada em fevereiro de 2026) mostra htmx mantendo seu status de "mais admirada" entre devs que experimentaram, enquanto a satisfação com React caiu pro ponto mais baixo mesmo com 83.6% de uso. Alguma coisa tá mudando, mas o quê exatamente?
Isso não é mais um artigo "htmx bom, React ruim". É um framework de decisão. No final, você vai saber exatamente quando htmx é a escolha certa, quando React ainda é insubstituível, e quando a resposta é "usa os dois".
A Divisão Arquitetural Central
Antes de comparar features, você precisa entender a diferença fundamental. htmx e React não usam apenas APIs diferentes — representam filosofias opostas sobre onde o estado da aplicação deve viver.
React: O Modelo de Aplicação Client-Side
React trata o navegador como um runtime de aplicação. Seu servidor é uma API que retorna JSON. Seu cliente é uma aplicação completa que gerencia estado, routing, renderização UI e side effects.
[Servidor] → JSON → [App React] → DOM
↑
Gerenciamento de Estado
Routing
Side Effects
Error Boundaries
Esse modelo é poderoso. Permite apps offline-first, atualizações otimistas, animações complexas, colaboração em tempo real e interfaces ricas. Mas é complexo também. Uma app React típica em 2026 envolve:
- Um meta-framework (Next.js, Remix ou similar)
- Uma abordagem de gerenciamento de estado (React Context, Zustand, Jotai, ou Server Components)
- Uma camada de data fetching (TanStack Query, SWR, ou loaders nativos do framework)
- Um pipeline de build (Vite, Turbopack ou Webpack)
- Configuração de TypeScript
- Infraestrutura de testes (Vitest, Playwright, Testing Library)
São seis camadas de tooling antes de escrever uma única linha de lógica de negócio.
htmx: O Modelo Hipermídia
htmx trata o navegador como um visualizador de documentos que consegue trocar partes. Seu servidor retorna fragmentos HTML. O cliente não tem estado, não tem lógica de routing, não tem build step.
[Servidor] → HTML → [Navegador + htmx] → DOM (swap do alvo)
O servidor é a aplicação. O navegador é o renderer. htmx é a ponte que permite atualizar partes da página sem reload completo.
<!-- Formulário de busca que atualiza resultados sem reload --> <input type="search" name="q" hx-get="/search" hx-trigger="input changed delay:300ms" hx-target="#results"> <div id="results"> <!-- Servidor retorna fragmentos HTML aqui --> </div>
É isso. Sem arquivo JavaScript. Sem build step. Sem gerenciamento de estado. O servidor processa a busca, renderiza os resultados como HTML, e htmx faz o swap do div #results. A interação inteira é definida em atributos HTML.
Onde htmx Ganha: Os 80% das Aplicações Web
Aqui vai a verdade desconfortável que defensores de React não querem ouvir: a maioria das apps web são interfaces CRUD com formulários, tabelas, filtros e navegação. Não precisam de um runtime de aplicação client-side. Precisam de um servidor que renderize HTML e uma forma de atualizar partes da página sem recarregar.
1. Dashboards Admin e Ferramentas Internas
A maior categoria onde htmx domina. Um painel admin é fundamentalmente uma coleção de:
- Tabelas com ordenação, filtros e paginação
- Formulários pra criar e editar registros
- Modais de confirmação
- Toast notifications pra feedback
Com htmx, cada um desses é um round-trip ao servidor que retorna um fragmento HTML:
<!-- Header de tabela ordenável --> <th hx-get="/users?sort=name&dir=asc" hx-target="#user-table-body" hx-indicator="#loading"> Nome ↕ </th> <!-- Deletar com confirmação --> <button hx-delete="/users/42" hx-confirm="Deletar este usuário?" hx-target="closest tr" hx-swap="outerHTML swap:500ms"> Deletar </button> <!-- Edição inline --> <td hx-get="/users/42/edit-name" hx-trigger="dblclick" hx-swap="innerHTML"> João Silva </td>
A mesma funcionalidade em React exige:
// Gerenciamento de estado pro sort const [sortConfig, setSortConfig] = useState({ key: 'name', dir: 'asc' }); // Data fetching com TanStack Query const { data, isLoading, refetch } = useQuery({ queryKey: ['users', sortConfig, filters, page], queryFn: () => fetchUsers({ ...sortConfig, ...filters, page }), }); // Mutation de delete com update otimista const deleteMutation = useMutation({ mutationFn: deleteUser, onMutate: async (userId) => { await queryClient.cancelQueries(['users']); const previous = queryClient.getQueryData(['users']); queryClient.setQueryData(['users'], (old) => old.filter(u => u.id !== userId) ); return { previous }; }, onError: (err, userId, context) => { queryClient.setQueryData(['users'], context.previous); }, onSettled: () => queryClient.invalidateQueries(['users']), }); // Estado do modal de confirmação const [deleteTarget, setDeleteTarget] = useState(null); const [showConfirm, setShowConfirm] = useState(false);
A versão htmx são 8 linhas de atributos HTML. A versão React são 25+ linhas de JavaScript antes de encostar no JSX. E a versão React tem mais pontos de falha: cache stale, bugs de rollback otimista, race conditions entre queries, e memory leaks de subscriptions.
2. Formulários Multi-etapa e Wizards
htmx lida com validação parcial e fluxos multi-etapa naturalmente porque o servidor controla o estado:
<!-- Etapa 1: Servidor valida e retorna etapa 2 --> <form hx-post="/onboarding/step-1" hx-target="#wizard-container" hx-swap="innerHTML"> <input name="email" type="email" required> <input name="company" required> <button type="submit">Próximo</button> </form>
O servidor valida a etapa 1, salva o progresso na sessão e retorna o HTML da etapa 2. Sem gerenciamento de estado de formulário client-side. Sem Formik, sem React Hook Form, sem schemas Zod conectados a componentes do cliente.
3. Sites de Conteúdo com Seções Dinâmicas
Blogs, sites de documentação, páginas de produto de e-commerce — onde o conteúdo principal é server-rendered mas você precisa de interações dinâmicas (adicionar ao carrinho, busca ao vivo, seção de comentários).
<!-- Adicionar ao carrinho sem reload --> <button hx-post="/cart/add" hx-vals='{"productId": "abc123", "qty": 1}' hx-target="#cart-count" hx-swap="innerHTML"> Adicionar ao Carrinho </button> <!-- Seção de comentários ao vivo --> <div hx-get="/posts/42/comments" hx-trigger="load, every 30s" hx-swap="innerHTML"> <!-- Comentários carregam aqui --> </div>
O Argumento de Performance
Pra apps server-driven, htmx ganha em toda métrica de performance que importa:
| Métrica | htmx | React SPA |
|---|---|---|
| Bundle JavaScript | ~14 KB (htmx em si) | 150-400 KB (framework + app) |
| Time to Interactive | Quase instantâneo (sem hydration) | Atrasado (requer hydration) |
| Score INP | Excelente (execução JS mínima) | Variável (depende da árvore de componentes) |
| Carga do servidor | Maior (renderiza HTML) | Menor (retorna JSON) |
| Cacheabilidade CDN | Excelente (fragmentos HTML cacheiam bem) | Ruim (respostas JSON dinâmicas) |
A única área onde React ganha é carga do servidor. Renderizar HTML server-side custa mais CPU que serializar JSON. Mas em 2026, com edge computing e streaming HTML, esse tradeoff favorece cada vez mais htmx pra maioria das aplicações.
Onde React Ainda É Insubstituível
Agora o outro lado. Existem aplicações onde htmx genuinamente não compete, e fingir o contrário não é honesto.
1. Editores de Texto Rico e Componentes Interativos Complexos
Construir algo como Notion, Google Docs, ou um whiteboard colaborativo exige gerenciar estado local complexo com granularidade de microsegundos. Cada keystroke, posição do cursor, range de seleção e operação de formatação precisa ser tratada client-side. Um round-trip ao servidor pra cada caractere? Latência insuportável.
htmx não dá conta disso. 200ms de round-trip pro servidor por keystroke não rola. Isso é território de aplicação client-side.
2. Aplicações Offline-First
Se sua app precisa funcionar sem internet — tipo app de serviço em campo, app de notas mobile ou sistema POS — htmx é arquiteturalmente incompatível. htmx precisa de um servidor pra cada interação. Sem servidor, sem interação.
3. Features de Colaboração em Tempo Real
Edição simultânea estilo Google Docs, jogos multiplayer, ferramentas de design colaborativo — qualquer coisa onde múltiplos usuários modificam estado compartilhado em alta frequência. O modelo request-response do htmx não encaixa nesse padrão.
4. Interações UI de Alta Frequência
Drag-and-drop, visualizações de dados interativas (D3.js), UIs pesadas em animação, editores canvas e interfaces tipo jogo precisam de responsividade na taxa de quadros do lado do cliente.
Matriz de Decisão
| Caso de Uso | htmx | React | Ambos |
|---|---|---|---|
| Dashboards admin | ✅ Melhor | ⚠️ Overkill | — |
| Apps CRUD | ✅ Melhor | ⚠️ Overkill | — |
| Formulários multi-etapa | ✅ Bom | ✅ Bom | — |
| E-commerce | ✅ Bom | ✅ Bom | ✅ Melhor |
| Sites de conteúdo com interações | ✅ Melhor | ⚠️ Overkill | — |
| Editores de texto rico | ❌ Não rola | ✅ Necessário | — |
| Apps offline-first | ❌ Não rola | ✅ Necessário | — |
| Colaboração em tempo real | ❌ Ruim | ✅ Necessário | — |
| Dashboards de visualização | ⚠️ Limitado | ✅ Melhor | ✅ Bom |
| Builders drag-and-drop | ❌ Não rola | ✅ Necessário | — |
O Padrão "Use os Dois": Ilhas de Interatividade
A resposta mais pragmática em 2026 é geralmente "use os dois". A arquitetura se chama Ilhas de Interatividade — htmx cuida da estrutura da página, navegação e CRUD padrão, enquanto componentes React (ou Preact/Svelte) isolados cuidam das partes interativas complexas.
Como Funciona
<!-- Shell de página gerenciado por htmx --> <main> <!-- htmx cuida da navegação --> <nav hx-boost="true"> <a href="/dashboard">Dashboard</a> <a href="/analytics">Analytics</a> <a href="/settings">Configurações</a> </nav> <!-- htmx cuida da tabela/CRUD --> <section hx-get="/dashboard/table" hx-trigger="load" hx-target="this"> Carregando... </section> <!-- Ilha React pro gráfico interativo --> <div id="analytics-chart" data-config='{"range": "30d", "metrics": ["revenue", "users"]}'> </div> <script type="module"> import { renderChart } from './chart-island.js'; renderChart(document.getElementById('analytics-chart')); </script> </main>
GitHub usa esse padrão há anos — a maior parte do GitHub é HTML server-rendered com JavaScript específico pra componentes interativos como o editor de código, a árvore de arquivos e o builder de workflows do Actions.
Migração: Extraindo React da Sua SPA
Se você tá considerando sair de uma SPA React pra htmx, não faça um rewrite de uma vez. Use o padrão Strangler Fig: substitua páginas uma por vez, começando pelas mais simples.
Etapa 1: Identificar Páginas de Baixa Interação
Audite sua app React. Procure páginas que são essencialmente tabelas de dados com filtros, formulários de configuração, views de detalhe e views de lista/grid. Provavelmente representam 60-80% das suas páginas mas menos de 20% da complexidade interativa.
Etapa 2: Rotas Server-Side
Pra cada candidato, crie uma rota server-side que retorne HTML completo:
# Exemplo em Django def user_list(request): users = User.objects.filter(active=True) sort = request.GET.get('sort', 'name') if request.headers.get('HX-Request'): # Request htmx: retorna só o body da tabela return render(request, 'users/_table_body.html', {'users': users}) # Request de página completa: retorna página inteira return render(request, 'users/list.html', {'users': users})
O check do header HX-Request é o padrão chave. Mesma rota, mesma lógica, mas htmx recebe um fragmento HTML enquanto a navegação direta recebe a página completa.
Etapa 3: Manter React Onde Importa
Não migre seus componentes interativos. Mantenha o editor de texto rico em React, o quadro kanban com drag-and-drop, o widget de chat em tempo real. Encapsule eles como ilhas autocontidas que montam em páginas server-rendered.
ROI da Migração
Times que migraram SPAs React pesadas em CRUD pra htmx reportam consistentemente:
- 40-60% de redução em código frontend
- Entrega de features mais rápida pra telas CRUD padrão
- Melhoria em Core Web Vitals (melhorias em LCP e INP por eliminar hydration)
- Debug simplificado (os logs do servidor contam a história toda)
O Fator Backend: htmx Brilha com Certos Stacks
Um aspecto subestimado do htmx é como ele desbloqueia times backend. Se seu time é principalmente de Go, Python, Ruby, Rust, PHP ou Java, htmx permite construir apps web interativas sem aprender React.
Ecossistema htmx + Linguagem Backend
| Backend | Integração htmx | Engine de Templates | Exemplos em Produção |
|---|---|---|---|
| Go | Excelente (templ, stdlib) | templ, html/template | Dashboards de infra |
| Python/Django | Excelente (django-htmx) | Django templates | Painéis admin, CMS |
| Ruby/Rails | Excelente (Turbo + htmx) | ERB, Haml | Interfaces admin SaaS |
| Rust/Axum | Crescendo (askama, maud) | askama, maud | Dashboards de alta performance |
| PHP/Laravel | Excelente (Blade nativo) | Blade | Admin e-commerce, CRM |
| Java/Spring | Bom (Thymeleaf) | Thymeleaf | Apps CRUD enterprise |
Erros Comuns com htmx (E Como Evitar)
1. Tratar htmx Como um Framework Client-Side
O maior erro é gerenciar estado no cliente. Se você tá escrevendo JavaScript pra rastrear qual tab tá ativa ou quais filtros estão aplicados, tá brigando com a arquitetura do htmx.
Errado:
let activeFilters = []; document.querySelectorAll('.filter-checkbox').forEach(cb => { cb.addEventListener('change', () => { if (cb.checked) activeFilters.push(cb.value); else activeFilters = activeFilters.filter(f => f !== cb.value); htmx.ajax('GET', `/items?filters=${activeFilters.join(',')}`, '#results'); }); });
Certo:
<!-- Deixe o servidor gerenciar o estado dos filtros --> <form hx-get="/items" hx-target="#results" hx-trigger="change"> <label><input type="checkbox" name="filter" value="active"> Ativos</label> <label><input type="checkbox" name="filter" value="premium"> Premium</label> <label><input type="checkbox" name="filter" value="new"> Novos</label> </form>
2. Fazer Requests Demais
htmx facilita requests pro servidor, o que pode deixar a app tagarela. Use modificadores de hx-trigger pra debounce e throttle:
<input hx-get="/search" hx-trigger="input changed delay:300ms" hx-target="#results" name="q">
3. Esquecer dos Estados de Loading
htmx fornece o padrão hx-indicator pra estados de loading. Use sempre:
<button hx-post="/process" hx-indicator="#spinner"> Enviar <img id="spinner" class="htmx-indicator" src="/spinner.svg"> </button>
Reality Check 2026
A indústria tá convergindo pra um meio-termo pragmático:
-
SPAs não morreram. Apps complexas e interativas ainda precisam de frameworks client-side. React, Vue e Svelte não vão a lugar nenhum.
-
SPAs tão sendo usadas demais. Apps demais que são fundamentalmente CRUD server-driven foram construídas como SPAs client-side porque "é assim que se faz agora". htmx expõe essa sobreengenharia.
-
A melhor arquitetura é a que encaixa no seu problema. Um clone do Notion precisa de React. Um dashboard admin precisa de htmx. Um produto SaaS provavelmente precisa dos dois.
-
htmx não é "voltar no tempo". Não é desenvolvimento da era PHP. É uma abordagem moderna que aproveita a semântica HTTP, navegadores modernos e o fato de que a maioria das interações são padrões request-response. A infraestrutura de server-rendering de 2026 torna essa abordagem mais rápida e escalável que nunca.
-
A fadiga do ecossistema JavaScript é real. O crescimento do htmx não é só mérito técnico. É também devs cansados de manter diretórios
node_modulesde 200MB, debugar configurações de webpack e aprender uma nova biblioteca de gerenciamento de estado a cada seis meses.
Escolha a arquitetura com base no que sua aplicação realmente precisa, não no que o Twitter diz que tá na moda. Pra maioria das apps web, isso significa menos JavaScript, não mais.
Explore ferramentas relacionadas
Experimente estas ferramentas gratuitas do Pockit