HTMX & Hono - the new stack

HTMX is a javascript library that allows you to build an interactive application without having to write any javascript, see this example:

<button hx-get=“/latest” hx-target=“#images”>Load</button>

The hx-post attributes tells HTMX to make a GET request to /latest and insert the response into an element with the id of images, this is HTMX in a nutshell, there are lots of other supporting features but being able to make requests and update the dom with a response is its bread and butter.

HTMX is a return to the old web pre SPA’s, using http verbs as intended and a focus on web standards, it reminds me of building simple CRUD apps in asp .net and binding form data to a model on the server.

There’s no JSON api’s needed here, you just return HTML and it is inserted into the dom, initially this sounds bad, returning all that HTML on every request but HTMX is doing some trickier to update the DOM in an efficient manner.

It’s a big mental shift coming from “everything is a single page app”, but it takes away the biggest issue with SPAs, state management, you don’t need to worry about it with HTMX, you don’t need to touch any javascript to create a sophisticated experience. It is not ideal for every use case, need to create a sophisticated code editor, might be better to use a javascript framework, but it would still be possible along side HTMX.

The big benefits for me are its simplicity, it’s very easy to get something up and running very quickly, it is not a massive API to pick up and understand. There a no dependencies, not having to install a million npm packages to render some html. It’s basic web stuff, making requests and posting forms and validating them in a standard way, returning HTML rather than a JSON object of a random shape or having to setup GraphQL just to render some HTML. I started my journey into web development well before a single page app was a thing and I suspect many new devs go straight to a juicy javascript framework and miss out on understanding some of the basic technologies that run the web.

Everything is not a spa, it is nice to have a simple alternative to having to use a huge framework to build something simple and not really be tied into that framework, I think it would be a lot easier replacing your backend of choice in an HTMX than with a full javascript framework.

Hono is a javascript framework that integrates nicely with Cloudflare and other server less platforms, it also supports HTML templating and JSX which makes it the ideal partner for an HTMX application.

Example Let look at an example of how a user would login then be taken to a dashboard page with HTMX.

User goes to the login page of your site, say /login, your server sends the HTML for the login page in the response, user fills in the form, you can use native browser form validation here or make inline calls to validate each form input on the server

<input type=“text” name=“name” hx-post=“/validate” />

The /validate endpoint returns the html for the input along with any validation message it needs to display.

app.post("/validate", async (c) => {
   const {name} = await c.req.parseBody();
   if(nameIsValid(name)) {
       return (<NameInput name={name} error={"Name is invalid"} />);
   }
   return (<NameInput name={name} />);
});

In the endpoint we can validate the ‘name’ property and return the name component with the error if it failed validation or without if it passes.

We can attach HTMX attributes to handle form submissions and HTMX will respect input validation attributes and will submit if inputs fail validation.

<form method=“post” hx-post=“/submit” hx-target=“#main”>

User submits the form to submit, you can either return the dashboard page straight away or do something a little fancier, show a success message for a few seconds then navigate to the dashboard page:

return c.html(<div hx-trigger={"load delay:2s"} hx-get={‘/dashboard} hx-target={"#main"} hx-swap={"outerHTML"}>
    Saved
</div>);

Here we are using a trigger that will call the get endpoint after 2 seconds delay and insert the response onto the element with id of main, hx-swap attributes says replace the target element outerHTML, the whole element rather than the default which is innerHTML.

To return the dashboard page, in your submit endpoint if you have successfully validated the form you can return the dashboard HTML and set the header ‘HX-Push-Url’ to /dashboard which sets the browser url adds an entry into the history, which means the back button works to return to the form, or the user can refresh and remain on the dashboard, assuming the endpoint /dashboard returns the dashboard HTML.

c.header('HX-Push-Url', '/app')
return c.html(<Dashboard  />)

When your setting the browser url like this you want to make sure page refresh works correctly, so your endpoint returns the full page HTML rather than a fragment.

HTMX has lots of other functionality, you can add animations and view transitions and you can dip into javascript and hook onto events if you need to.

© 2024 Timney.