HTMX
htmx es una biblioteca que le permite acceder a funciones modernas del navegador directamente desde HTML, en lugar de utilizar javascript.
htmx utiliza atributos HTML personalizados para agregar interactividad a los elementos HTML existentes en una página web sin tener que escribir JavaScript adicional.
<button
hx-get="/api/hello"
hx-trigger="click"
hx-target="#id-hello"
hx-swap="innerHTML"
>
Click Me!
</button>
<div id="id-hello"></div>
Esto hace que sea más fácil para los desarrolladores crear aplicaciones web complejas sin tener que preocuparse por la complejidad de JavaScript.
Links de interés
Introducción
htmx le brinda acceso a AJAX, transiciones CSS, WebSockets y eventos enviados por el servidor directamente en HTML, utilizando atributos, para que pueda crear interfaces de usuario modernas con la simplicidad y el poder del hipertexto.
- ¿Por qué solo deberían los atributos
<a>
y<form>
pueder realizar solicitudes http? - ¿Por qué solo los eventos
click
ysubmit
deberían activarlos? - ¿Por qué deberían estar disponibles solo los métodos
GET
yPOST
?
Servidor con express
npm init -y
npm i express
npm i -D nodemon
package.json
{
"name": "01-dev",
"type": "module",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"dev": "nodemon index.js",
"start": "node index.js"
},
"keywords": [],
"author": "bluuweb",
"license": "ISC",
"dependencies": {
"express": "^4.18.2"
},
"devDependencies": {
"nodemon": "^3.0.1"
}
}
index.js
import express from "express";
const app = express();
// static files www/index.html
app.use(express.static("www"));
app.get("/api/hello", (req, res) => {
res.send("Hello World!");
});
app.listen(3000, () => {
console.log("Server is running on port 3000");
});
www/index.html
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0"
/>
<title>HTMX</title>
</head>
<body>
<h1>HTMX</h1>
</body>
</html>
npm run dev
htmx
- Instalación a través de CDN
- Comenzar a jugar con los atributos
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0"
/>
<title>HTMX</title>
<script
src="https://unpkg.com/htmx.org@1.9.6"
integrity="sha384-FhXw7b6AlE/jyjlZH5iHa/tTe9EpJ1Y55RjcgPbjeWMskSxZt1v9qkxLJWNJaGni"
crossorigin="anonymous"
></script>
</head>
<body>
<h1>HTMX</h1>
<button
hx-get="/api/hello"
hx-trigger="click"
hx-target="#id-hello"
hx-swap="innerHTML"
>
Click Me!
</button>
<div id="id-hello"></div>
</body>
</html>
Esto le dice a htmx:
Cuando un usuario de clic en el botón, emite una solicitud GET
a /api/hello
y reemplaza el contenido de #id-hello
con la respuesta.
Características
- Ahora cualquier elemento HTML puede realizar solicitudes HTTP.
- Ahora cualquier evento puede activar una solicitud HTTP.
- Ahora cualquier método HTTP puede ser utilizado. (GET, POST, PUT, DELETE, etc.)
- Ahora cualquier elemento HTML puede ser un objetivo de solicitud HTTP.
Atributos
Ajax
hx-get
: Realiza una solicitudGET
a la URL especificada.hx-post
: Realiza una solicitudPOST
a la URL especificada.hx-put
: Realiza una solicitudPUT
a la URL especificada.hx-delete
: Realiza una solicitudDELETE
a la URL especificada.hx-patch
: Realiza una solicitudPATCH
a la URL especificada.hx-params
: Especifica los parámetros de la solicitud.hx-headers
: Especifica los encabezados de la solicitud.
<div
hx-get="/api/time"
hx-trigger="every 1s"
></div>
app.get("/api/time", (req, res) => {
res.send(new Date().toLocaleTimeString());
});
Swapping hx-swap
htmx ofrece algunas formas diferentes de intercambiar el HTML devuelto al DOM. De forma predeterminada, el contenido reemplaza el elemento de destino con innerHTML (como vimos en el ejemplo anterior). más info aquí
hx-swap="innerHTML"
: Reemplaza el contenido del elemento de destino con el contenido devuelto.hx-swap="outerHTML"
: Reemplaza el elemento de destino con el contenido devuelto.hx-swap="afterbegin"
: Inserta el contenido devuelto al principio del elemento de destino.hx-swap="beforebegin"
: Inserta el contenido devuelto antes del elemento de destino.hx-swap="afterend"
: Inserta el contenido devuelto después del elemento de destino.hx-swap="none"
: No intercambia nada.
<div
hx-get="/api/time"
hx-trigger="every 1s"
hx-swap="innerHTML"
>
Cargando...
</div>
Target hx-target
Si desea que la respuesta se envíe a un elemento diferente al elemento que activó la solicitud, puede usar el atributo hx-target
para especificar el destino.
hx-target="#id"
: El elemento con el id especificado.hx-target=".class"
: El primer elemento con la clase especificada.hx-target="closest .class"
: El elemento más cercano con la clase especificada.hx-target="self"
: El elemento que activó la solicitud.hx-target="next"
: El siguiente elemento después del elemento que activó la solicitud.hx-target="prev"
: El elemento anterior al elemento que activó la solicitud.hx-target="parent"
: El elemento padre del elemento que activó la solicitud.hx-target="body"
: El elemento body.hx-target="window"
: La ventana actual.
<button
hx-patch="/api/likes"
hx-trigger="click"
hx-target="#id-likes"
hx-swap="innerHTML"
>
❤️ Likes <span id="id-likes">0</span>
</button>
let likes = 0;
app.patch("/api/likes", (req, res) => {
likes++;
res.send(likes.toString());
});
Trigger hx-trigger
El atributo hx-trigger
le permite especificar qué evento activará la solicitud. De forma predeterminada, el evento click
activa la solicitud.
hx-trigger="click"
: El evento click.hx-trigger="input"
: El evento input.hx-trigger="change"
: El evento change.hx-trigger="keyup"
: El evento keyup.hx-trigger="keydown"
: El evento keydown.hx-trigger="keypress"
: El evento keypress.hx-trigger="mouseover"
: El evento mouseover.hx-trigger="mouseout"
: El evento mouseout.hx-trigger="focus"
: El evento focus.hx-trigger="blur"
: El evento blur.hx-trigger="load"
: El evento load.hx-trigger="unload"
: El evento unload.hx-trigger="submit"
: El evento submit.hx-trigger="every 1s"
: El evento cada 1 segundo.
<input
type="text"
name="username"
placeholder="Search..."
hx-post="/api/search"
hx-trigger="keyup"
hx-target="#id-name"
hx-swap="innerHTML"
/>
<ul id="id-name"></ul>
// urlencoded form data
app.use(express.urlencoded({ extended: false }));
const users = ["Alice", "Bob", "Carol"];
app.post("/api/search", (req, res) => {
const { username } = req.body;
const result = users.filter((user) =>
user.toLowerCase().includes(username.toLowerCase())
);
const html = result.map((user) => `<li>${user}</li>`).join("");
res.send(html);
});
Ejemplos
Delete
<style>
tr.htmx-swapping td {
opacity: 0;
transition: opacity 1s ease-out;
}
</style>
<table class="table delete-row-example">
<thead>
<tr>
<th>Name</th>
<th>Email</th>
<th>Status</th>
<th></th>
</tr>
</thead>
<tbody
hx-confirm="Are you sure?"
hx-target="closest tr"
hx-swap="outerHTML swap:1s"
>
<tr>
<td>Angie MacDowell</td>
<td>angie@macdowell.org</td>
<td>Active</td>
<td>
<button
class="btn btn-danger"
hx-delete="/api/contact/1"
>
Delete
</button>
</td>
</tr>
<tr>
<td>Angie MacDowell 2</td>
<td>angie@macdowell.org 2</td>
<td>Active</td>
<td>
<button
class="btn btn-danger"
hx-delete="/api/contact/2"
>
Delete
</button>
</td>
</tr>
</tbody>
</table>
app.delete("/api/contact/:id", (req, res) => {
const { id } = req.params;
console.log({ id });
res.status(200).send();
});