Ora che sappiamo a cosa serve htmx e come installare la libreria, scopriamo come utilizzarla all'interno di un'applicazione web. Htmx utilizza speciali attributi hx-[nome-attributo]
o data-hx-[nome-attributo]
per aggiungere funzionalità ad HTML. Qui analizzeremo i principali attributi, quelli che non mancano mai in un'applicazione potenziata da htmx.
Invio di richieste HTTP
Con il puro e semplice HTML, non è possibile inviare richieste che non siano GET
o POST
. Con htmx, ogni elemento del DOM può inviare al server un qualsiasi tipo di richiesta tramite i corrispondenti attributi.
Quello che segue è l'elenco completo degli attributi che specificano il tipo di richiesta HTTP:
hx-get
.hx-post
.hx-put
.hx-patch
.hx-delete
.
Il valore dell'attributo stabilisce la risorsa verso cui trasmettere la richiesta. Ed ecco come inviare una richiesta GET
con un pulsante:
<button
hx-get="/hello"
>
Click me!
</button>
Al verificarsi dell'evento stabilito, in questo caso il normale clic sul pulsante, htmx esegue una richiesta AJAX del tipo stabilito (GET
) indirizzata alla risorsa specificata.
Eventi nativi ed eventi htmx
Di default, una richiesta HTTP viene attivata al verificarsi dei seguenti eventi:
- evento
change
per gli elementiinput
,textarea
eselect
; - evento
submit
per iform
; - evento
click
per tutti gli altri elementi.
Nel puro HTML, non è possibile fare altro. Htmx, invece, dispone di uno speciale attributo, hx-trigger
, che permette di associare ad un qualsiasi elemento del DOM uno o più eventi al verificarsi dei quali trasmettere una richiesta HTTP. Ad esempio, potremmo attivare una richiesta AJAX al passaggio del cursore del mouse su un pulsante, invece che attendere il classico clic:
<button
hx-get="/hello"
hx-trigger="mouseenter"
>
Hover me!
</button>
In questo esempio, il passaggio del mouse sul pulsante attiverà una richiesta GET
indirizzata all'endpoint hello.
Modificatori, filtri ed eventi speciali
Htmx dispone anche di modificatori e filtri di eventi, oltre ad una serie di eventi speciali. Un esempio di modificatore è once
, che fa sì che un evento attivi una richiesta HTTP una sola volta:
<button
hx-get="/hello"
hx-trigger="mouseenter once"
>
Hover over me only once!
</button>
I filtri sono delle espressioni JavaScript che attivano l'evento quando vengono valutate true
. I filtri vengono aggiunti all'evento e contrassegnati da parentesi quadre:
<button
hx-get="/hello"
hx-trigger="click[ctrlKey]"
>
CTRL + Click!
</button>
Nell'esempio qui sopra, l'evento viene attivato dalla combinazione CTRL + clic
. Nel prossimo esempio creeremo invece una scorciatoia da tastiera:
<button
hx-get="/partials/users/"
hx-trigger="click, keyup[ctrlKey && key == 'u']"
>
Load users!
</button>
Qui la richiesta viene attivata al clic sul pulsante o al verificarsi dell'evento keyup
con la combinazione di tasti Ctrl + u
. Attenzione però. Questo avviene solo quando il pulsate ha il focus.
Per estendere la combinazione di tasti all'intero documento, ossia fare in modo che la scorciatoia da tastiera attivi la richiesta indipendentemente dall'elemento del DOM che ha il focus, è possibile combinare un filtro con un modificatore.
Possiamo utilizzare, ad esempio, il modificatore from:
per specificare un selettore CSS che individua l'elemento target dell'evento. Se volessimo intercettare l'evento keyup
indipendentemente dall'elemento che ha il focus, potremmo utilizzare il seguente codice:
<button
hx-get="/partials/users/"
hx-trigger="click, keyup[ctrlKey && key == 'u' from:body]"
>
Load users!
</button>
Htmx supporta anche alcuni eventi speciali:
load
: si attiva quando l'elemento viene caricato per la prima volta;revealed
: si attiva quando un elemento scorre per la prima volta nel viewport;intersect
: si attiva quando un elemento interseca per la prima volta il viewport. Questo evento supporta due opzioni:root:<selector>
: un selettore CSS per l'elemento root;threshold:<float>
: un numero compreso tra 0.0 e 1.0 che indica la dimensione dell'intersezione che attiva l'evento.
Risposte HTML e risposte htmx
A seguito di una richiesta HTTP inviata tramite HTML, la risposta sarà un intero documento che andrà a sostituire completamente la pagina da cui è stata inviata la richiesta.
Nel caso di richieste attivate da htmx, le risposte possono essere bit parziali di HTML. Nelle interazioni basate su htmx, non si sostituisce l'intero documento ma si ricorre alla "transclusione" che consiste nell'iniettare il codice della risposta all'interno di un elemento del DOM.
Questo permette di risparmiare larghezza di banda e ridurre i tempi di caricamento delle risorse. Il contenuto complessivo trasferito dal server al client sarà minore e non sarà necessario rielaborare il tag head
con fogli di stile e script
. A tal fine, htmx dispone dell'attributo hx-target
.
Quello che segue è un esempio dal mondo reale. Abbiamo creato un "partial" nella cartella src/pages/partials
di un'installazione Astro e l'abbiamo nominato users.astro
:
---
export const partial = true;
---
<ul>
<li>First user</li>
<li>Second user</li>
<li>Third user</li>
</ul>
Si tratta di un semplice blocco di codice HTML. Possiamo iniettarlo all'interno di un elemento del DOM di un'applicazione al clic su un pulsante. Ecco il codice htmx:
<button
hx-get="/partials/users/"
hx-target="#outcome"
>
Load users!
</button>
<div id="outcome"></div>
L'attributo hx-target
definisce l'elemento in cui verrà renderizzato il contenuto della risposta.
Quando un utente della pagina farà clic sul pulsante, il codice HTML del partial di Astro sarà iniettato nella div#outcome
senza ricaricare la pagina:
<button
hx-get="/partials/users/"
hx-target="#outcome"
>
Load users!
</button>
<div id="outcome">
<ul>
<li>First user</li>
<li>Second user</li>
<li>Third user</li>
</ul>
</div>
In questo esempio, il target è individuato tramite un selettore CSS e il contenuto è semplicemente iniettato all'interno dell'elemento. Ma htmx permette di personalizzare con precisione il modo in cui il contenuto della risposta deve essere inserito all'interno del DOM.
L'inserimento della risposta nel DOM
Non è detto che iniettare il contenuto della risposta all'interno di un elemento del DOM sia esattamente ciò che vogliamo. L'attributo hx-swap
consente di specificare esattamente il modo in cui il contenuto deve essere scambiato nel DOM. hx-swap
può assumere uno dei seguenti valori:
innerHTML
: è l'impostazione predefinita. Htmx sostituisce il codice HTML contenuto nell'elemento target.outerHTML
: sostituisce l'intero elemento target.beforebegin
: inserisce la risposta prima dell'elemento target.afterbegin
: inserisce la risposta prima del primo elemento figlio dell'elemento target.beforeend
: inserisce la risposta dopo l'ultimo figlio dell'elemento target.afterend
: inserisce la risposta dopo l'elemento target.delete
: rimuove l'elemento target dal DOM, indipendentemente dalla risposta.none
: non viene eseguito alcuno scambio, è utilizzato quando si lavora solo sugli header della risposta.
I casi d'uso possono essere i più diversi. Ad esempio, beforeend
può essere utilizzato per implementare l'infinite scrolling su una pagina. Nell'esempio precedente, potremmo sostituire interamente l'elemento div#outcome
invece di iniettare il contenuto della risposta al suo interno:
<button
hx-get="/partials/users/"
hx-target="#outcome"
hx-swap="outerHTML"
>
Load users!
</button>
<div id="outcome"></div>
Al click sul pulsante, htmx genererebbe il seguente codice:
<button
hx-get="/partials/users/"
hx-target="#outcome"
hx-swap="outerHTML"
>
Load users!
</button>
<ul>
<li>First user</li>
<li>Second user</li>
<li>Third user</li>
</ul>
L'attributo hx-swap
viene utilizzato anche per aggiungere animazioni tramite le transizioni CSS e la View Transition API.
Documentazione online
In questa lezione abbiamo descritto gli attributi htmx di utilizzo più frequente, quelli che utilizzeremo nelle prossime lezioni per sviluppare un'applicazione htmx.
Per l'elenco completo delle funzionalità e degli attributi della libreria, facciamo rinvio alle seguenti risorse:
- Documentazione online.
- Reference.
- Extending HTML As Hypermedia e Htmx patterns dal libro Hypermedia Systems degli sviluppatori di htmx.