Back

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étricahtmxReact SPA
Bundle JavaScript~14 KB (htmx em si)150-400 KB (framework + app)
Time to InteractiveQuase instantâneo (sem hydration)Atrasado (requer hydration)
Score INPExcelente (execução JS mínima)Variável (depende da árvore de componentes)
Carga do servidorMaior (renderiza HTML)Menor (retorna JSON)
Cacheabilidade CDNExcelente (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 UsohtmxReactAmbos
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

BackendIntegração htmxEngine de TemplatesExemplos em Produção
GoExcelente (templ, stdlib)templ, html/templateDashboards de infra
Python/DjangoExcelente (django-htmx)Django templatesPainéis admin, CMS
Ruby/RailsExcelente (Turbo + htmx)ERB, HamlInterfaces admin SaaS
Rust/AxumCrescendo (askama, maud)askama, maudDashboards de alta performance
PHP/LaravelExcelente (Blade nativo)BladeAdmin e-commerce, CRM
Java/SpringBom (Thymeleaf)ThymeleafApps 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:

  1. 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.

  2. 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.

  3. 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.

  4. 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.

  5. 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_modules de 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.

htmxReactFrontendArchitectureWeb DevelopmentPerformance

Explore ferramentas relacionadas

Experimente estas ferramentas gratuitas do Pockit