Introducción a htmx 4
Introducción a htmx 4
htmx es una librería que extiende el HTML para que cualquier elemento pueda hacer una petición HTTP y reemplazar cualquier parte de la página con el HTML que devuelve el servidor. Nada más. No hay componentes, no hay estado en el cliente, no hay build.
<button hx-post="/clicked" hx-target="#resultado" hx-swap="innerHTML">
Haz clic
</button>
<div id="resultado"></div>
Ese botón hace POST /clicked, toma el HTML de la respuesta y lo mete dentro de #resultado.
Con eso ya entendiste el 60% de htmx: el resto son matices sobre cuándo se dispara,
a dónde va y cómo se inserta.
El problema que resuelve
El HTML original tiene una limitación arbitraria: sólo los enlaces y los formularios pueden hacer peticiones, sólo con GET y POST, y el resultado siempre reemplaza la página entera.
flowchart LR
subgraph HTML["HTML nativo"]
A["<a> y <form>"] --> B["GET / POST"] --> C["Reemplaza toda la página"]
end
subgraph HTMX["HTML + htmx"]
D["Cualquier elemento"] --> E["GET/POST/PUT/PATCH/DELETE"] --> F["Reemplaza cualquier fragmento"]
end
htmx completa las cuatro casillas que faltaban:
- Cualquier elemento puede disparar una petición, no sólo
<a>y<form>. - Cualquier verbo HTTP, no sólo GET y POST.
- Cualquier evento del DOM la puede disparar, no sólo el clic o el submit.
- Cualquier parte del DOM puede recibir la respuesta, no sólo el documento completo.
Aplicaciones dirigidas por hipermedia (HDA)
La arquitectura que propone htmx se llama Hypermedia-Driven Application. La regla central es: el servidor devuelve HTML, no JSON. El estado de la aplicación vive en el servidor y en el DOM; no hay una copia paralela en un store del cliente.
sequenceDiagram
participant U as Usuario
participant D as DOM
participant H as htmx
participant S as Servidor
U->>D: clic en el botón
D->>H: evento (hx-trigger)
H->>S: fetch("/tareas", {method:"POST"})
S-->>H: 200 text/html — fragmento
H->>D: swap en el target
D-->>U: UI actualizada
Comparado con una SPA:
| Aspecto | SPA (React/Vue) | HDA (htmx) |
|---|---|---|
| Formato de la respuesta | JSON | HTML |
| Dónde vive el estado | Store del cliente + servidor | Servidor + DOM |
| Renderizado | Cliente | Servidor |
| Build | Obligatorio | Ninguno |
| Duplicación de lógica | Validación y rutas en ambos lados | Sólo en el servidor |
| Peso del runtime | 45–120 kB+ | ~14 kB |
Esto no es “SPA vs htmx” como pelea religiosa: es una decisión de dónde poner la complejidad. Si tu aplicación es un editor de video, un canvas colaborativo o un cliente offline, necesitas estado en el cliente y htmx no es la herramienta. Si tu aplicación es un CRUD, un panel, un e-commerce o cualquier cosa donde el servidor ya es la fuente de la verdad, htmx elimina toda una capa.
Qué es htmx 4: “The Fetchening”
htmx 1 nació con soporte para IE11 y por eso usaba XMLHttpRequest. htmx 2 lo mantuvo por
compatibilidad. htmx 4 reescribe el núcleo sobre fetch(), y eso desbloquea todo lo demás:
flowchart TD
F["fetch() en el core"] --> S["Streaming nativo<br/>ReadableStream"]
F --> A["Aborto limpio<br/>AbortController"]
F --> E["Extensiones pueden<br/>reemplazar el fetch"]
F --> C["Menos código interno"]
C --> M["Morphing en el core<br/>innerMorph / outerMorph"]
C --> P["<hx-partial>"]
Los cambios que definen la versión 4:
1. fetch() reemplaza a XMLHttpRequest
Consecuencia directa: el modelo de eventos cambia (los eventos xhr:* desaparecen), el streaming
es de primera clase y las extensiones pueden interceptar o sustituir la función de red.
2. La herencia de atributos ahora es explícita
En htmx 2, un hx-target en un <div> lo heredaban todos sus hijos automáticamente. En htmx 4
hay que pedirlo con el modificador :inherited.
<!-- htmx 2: herencia implícita -->
<div hx-confirm="¿Seguro?">
<button hx-delete="/cuenta">Eliminar</button>
</div>
<!-- htmx 4: herencia explícita -->
<div hx-confirm:inherited="¿Seguro?">
<button hx-delete="/cuenta">Eliminar</button>
</div>
Es el cambio que más código rompe y el que más problemas de depuración elimina a largo plazo.
3. Morphing en el core
Idiomorph era una extensión; ahora innerMorph y outerMorph son estrategias de swap nativas.
Morphing significa que htmx compara el DOM viejo con el nuevo y toca sólo lo que cambió, en
lugar de destruir y recrear: se conserva el foco, la posición del scroll, el estado de los <video>
y de los widgets JS.
4. Los errores ahora hacen swap
En htmx 2, una respuesta 422 con el HTML de los errores de validación no se insertaba salvo que
lo forzaras con un listener. En htmx 4 se insertan todos los códigos excepto 204 y 304, y hay
un atributo dedicado, hx-status, para afinar el comportamiento por código.
5. El historial ya no cachea el DOM
htmx 2 guardaba snapshots del DOM en localStorage para el botón “atrás”, con todos los problemas
de tamaño e invalidación que eso implica. htmx 4 simplemente vuelve a pedir el contenido a la red.
Quien quiera el comportamiento anterior usa la extensión hx-history-cache.
6. Renombres importantes
| htmx 2 | htmx 4 | Qué hace |
|---|---|---|
hx-disable | hx-ignore | No procesar htmx en ese subárbol |
hx-disabled-elt | hx-disable | Deshabilitar elementos durante la petición |
htmx:afterRequest | htmx:after:request | Evento posterior a la petición |
defaultSwapStyle | defaultSwap | Config del swap por defecto |
Ese cruce de hx-disable es la trampa más peligrosa de la migración: el atributo existe en ambas
versiones y significa cosas distintas. Lo cubrimos a fondo en el
capítulo 17.
7. Novedades que no existían
<hx-partial>: un elemento que declara su propio target y swap, para actualizar varias zonas de la página desde una sola respuesta sin la gimnasia de los OOB swaps.hx-status: comportamiento por código HTTP.hx-optimistic: UI optimista declarativa.hx-live: bindings reactivos sobre atributos, clases, texto y estilos.htmx.timeout(): una promesa que resuelve tras un intervalo, usable dentro dehx-on.- HCON: una notación compacta para configuración en atributos.
Estado de la versión
| Rama | Estado hoy | Uso recomendado |
|---|---|---|
| 1.x | Soportada, con IE11 | Sólo mantenimiento legado |
| 2.x | Estable, latest en npm | Producción hoy |
| 4.0 | Beta (4.0.0-beta6) | Proyectos nuevos que toleran beta; aprendizaje |
El equipo de htmx ha declarado soporte perpetuo para la 2.x, así que migrar es una decisión, no una obligación. No hay htmx 3: el salto de número es deliberado para señalar la magnitud del cambio interno.
Qué necesitas para seguir el curso
Un editor, un navegador y cualquier servidor que devuelva HTML. Los ejemplos del curso usan Bun porque son tres líneas, pero puedes traducirlos a lo que uses:
// servidor.js — el "backend" mínimo del curso
Bun.serve({
port: 3000,
fetch(req) {
const url = new URL(req.url);
if (url.pathname === "/clicked") {
return new Response("<p>¡Hola desde el servidor!</p>", {
headers: { "Content-Type": "text/html" },
});
}
return new Response(Bun.file("./index.html"));
},
});
En el capítulo 2 lo montamos completo y hacemos la primera petición real.
Resumen
- htmx extiende el HTML para que cualquier elemento haga peticiones y actualice cualquier fragmento.
- El servidor devuelve HTML; el estado vive en el servidor y en el DOM.
- htmx 4 reescribe el core sobre
fetch(), lo que trae streaming, morphing y partials nativos. - La herencia de atributos pasa a ser explícita con
:inherited. - Los errores HTTP ahora se insertan por defecto, con
hx-statuspara afinarlo. - La versión actual es
4.0.0-beta6; la estable sigue siendo 2.x.
Siguiente: Instalación y primer proyecto →.