For et par år siden tenkte jeg det hadde vært lurt med en tjeneste som lot deg lese dokumentasjonen til Gren sitt standardbibliotek, og alle andre tilgjengelige bibliotek for Gren.
På den tiden var jeg også litt lei frontend-rammeverk, og bestemte meg derfor for å prøve en “old school” tilnærming:
Semantisk HTML, generert av backend. Enkel CSS. Minimalt, om noe, JavaScript.
Nå er ikke dette en case-study i bruk av enkel teknologi for å skrive moderne tjenester, så jeg skal nøye meg med å si dette: Jeg har sjelden vært så produktiv som når jeg skrev denne dokumentasjonssiden.
Faktisk vil jeg anbefale alle å ikke bruke mer kompleksitet enn de strengt tatt trenger. Når det er sagt så er det ikke alltid den enkle løsningen er fleksibel nok. JavaScript, i en eller annen form, kan derfor bli nødvendig.
Klarer vi å finne en middelvei mellom JQuery-suppe og en full Single Page Application?
![image: Slapp JavaScript med HTMX: «Har sjeldent vært så produktiv» image: Slapp JavaScript med HTMX: «Har sjeldent vært så produktiv»](https://www.kode24.no/images/81549709.jpg?imageId=81549709&x=0&y=0&cropw=100&croph=100&width=670&height=529)
Trenger ikke JavaScript
Bildet over viser forsiden til Grens dokumentasjonsside. Her kan du enkelt søke etter biblioteket du er interessert i å lese dokumentasjonen til ved å skrive inn et søkeord og trykke “Search”. Dette vil så laste en ny side med resultatene.
Så langt, så greit. Dette er bare et standard <form>-element.
Det som mangler er å få opp søkeforslag mens du skriver inn søkeord, slik at det går litt fortere å finne frem til riktig side hvis du allerede vet hva biblioteket heter.
Det er nok mange som tenker at de vil trenge JavaScript for å implementere søkeforslag, men dette er faktisk støttet i HTML i form av <datalist>-elementet.
![image: Slapp JavaScript med HTMX: «Har sjeldent vært så produktiv» image: Slapp JavaScript med HTMX: «Har sjeldent vært så produktiv»](https://www.kode24.no/images/81549737.jpg?imageId=81549737&x=0&y=0&cropw=100&croph=100&width=670&height=125)
I bildet over ser dere et fullt fungerende eksempel av et søkefelt med søkeforslag.
- I <input>-elementet ser vi en list-attributt som refererer til <datalist>-elementet med ID.
- <datalist>-elementet inneholder alle mulige søkeforslag.
- Nettleseren vil da filtrere vekk søkeforslag som ikke passer med det brukeren har skrevet inn.
Dette er hvordan det ser ut i nettleseren:
![image: Slapp JavaScript med HTMX: «Har sjeldent vært så produktiv» image: Slapp JavaScript med HTMX: «Har sjeldent vært så produktiv»](https://www.kode24.no/images/81549767.jpg?imageId=81549767&x=0&y=0&cropw=100&croph=100&width=670&height=555)
I teorien kan jeg altså generere et <datalist>-element som inneholder alle kjente navn på biblioteker i Gren og si meg ferdig. Dessverre er det ikke en veldig fremtidsrettet løsning, da det vil bli tregere og tregere etterhvert som flere biblioteker registreres på siden.
Det vi trenger for å komme helt i mål er å oppdatere listen med søkeforslag etter hvert som søkeordene skrives inn, og det får vi ikke til med ren HTML.
Det er jo synd, egentlig. Alt jeg vil er å oppdatere en liste i et konkret tilfelle. Det føles som noe som kunne vært definert av et attributt eller to istedenfor at det skal løses med programmering.
Det var nok det skaperen bak HTMX følte, også.
Løs det med HTMX
HTMX er et JavaScript-bibliotek som gir deg noen ekstra attributter for å lage en interaktiv nettside uten å skrive JavaScript selv.
Biblioteket er lite og godt dokumentert, og gir oss akkurat nok fleksibilitet til at vi kan unngå JavaScript i veldig mange tilfeller.
La oss benytte oss av et par attributter for å oppdatere søkeforslag mens brukeren skriver.
![image: Slapp JavaScript med HTMX: «Har sjeldent vært så produktiv» image: Slapp JavaScript med HTMX: «Har sjeldent vært så produktiv»](https://www.kode24.no/images/81549780.jpg?imageId=81549780&x=0&y=0&cropw=100&croph=100&width=670&height=448)
Attributene som starter med hx- er definert av HTMX, og gjør følgende:
- hx-get definerer et endepunkt som skal kalles. Når hx-get er definert på et inputfelt, så vil den nåværende verdien av inputfeltet bli inkludert i nettverkskallet. I vårt tilfelle kaller vi et endepunkt som returnerer et nytt <datalist>-element med relevante søkeforslag.
- hx-trigger bestemmer når endepunktet skal kalles. Her har vi definert at vi skal kalle endepunktet 500 millisekunder etter at søkefeltet har blitt endret.
- hx-target sier hvor responsen av nettverskallet skal havne. #terse_search_result er IDen til <datalist>-elementet med søkeforslag.
- hx-swap sier hvordan #terse_search_result skal oppdateres. Ved å spesifisere outerHTML sier vi at det eksisterende <datalist>-elementet skal fullstendig erstattes av hva som blir returnert fra /package/search/terse.
Det er alt vi trenger for å implementere søkeforslag. Resultatet kan du leke deg med på packages.gren-lang.org.
Konklusjon
Nå er dette et relativt enkelt eksempel, men det trengs ikke så mye fantasi for å se for seg at HTMX lar deg oppnå interaktive nettsider uten at det går på bekostning av lesbarhet eller behov for et JavaScript-rammeverk.
HTMX spiller på lag med HTML-valideringer og CSS-animasjoner. Gjennom utvidelser kan du endre innhold basert på innkommende Server Sent Events eller WebSocket-meldinger.
Du kan også flette sammen eksisterende HTML med ny HTML fra backend istedenfor å erstatte, som kan gjøre det lett å oppdatere et skjema med eventuelle feilmeldinger.
Kort fortalt gjør HTMX det enklere å holde seg til HTML og CSS uten å innføre for mye kompleksitet.
Det burde være godt nok i de fleste tilfeller.
![image: – Folk som deler kildekoden, skylder deg ingenting!](https://www.kode24.no/images/81536409.jpg?imageId=81536409&x=0&y=6.951871657754&cropw=100&croph=52.406417112299&width=321&height=193&compression=80 640w, https://www.kode24.no/images/81536409.jpg?imageId=81536409&x=0&y=6.951871657754&cropw=100&croph=52.406417112299&width=512&height=308&compression=80 1024w, https://www.kode24.no/images/81536409.jpg?imageId=81536409&x=0&y=6.951871657754&cropw=100&croph=52.406417112299&width=640&height=384&compression=70 320w)