Skip to content

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.

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

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 y submit deberían activarlos?
  • ¿Por qué deberían estar disponibles solo los métodos GET y POST?

Servidor con express

sh
npm init -y
npm i express
npm i -D nodemon

package.json

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

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

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>
sh
npm run dev

htmx

  • Instalación a través de CDN
  • Comenzar a jugar con los atributos
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>
    <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 solicitud GET a la URL especificada.
  • hx-post: Realiza una solicitud POST a la URL especificada.
  • hx-put: Realiza una solicitud PUT a la URL especificada.
  • hx-delete: Realiza una solicitud DELETE a la URL especificada.
  • hx-patch: Realiza una solicitud PATCH a la URL especificada.
  • hx-params: Especifica los parámetros de la solicitud.
  • hx-headers: Especifica los encabezados de la solicitud.
html
<div
  hx-get="/api/time"
  hx-trigger="every 1s"
></div>
js
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.
html
<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.
html
<button
  hx-patch="/api/likes"
  hx-trigger="click"
  hx-target="#id-likes"
  hx-swap="innerHTML"
>
  ❤️ Likes <span id="id-likes">0</span>
</button>
js
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.
html
<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>
js
// 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

html
<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>
js
app.delete("/api/contact/:id", (req, res) => {
  const { id } = req.params;
  console.log({ id });
  res.status(200).send();
});