:: krowemoh

Wednesday | 12 MAR 2025
Posts Links Other About Now

previous
next

Notes on Hypermedia Systems

2025-02-12

I've been meaning to read Hypermedia Systems for awhile now and I think it's finally time to give it a shot.

I want to build a RSS reader, link log and a blogmark site. I think this gives me a decent goal to build towards while reading the book.

Introduction

The first chapter is an introduction but it doesn't really explain what hypermedia is. It's only because I've already read other posts from the developer and I have briefly tried htmx that I understand what the book is talking about in relation to hypermedia.

The introduction mostly highlights that the current way of building applications is the through Javascript, AJAX and JSON APIs. It points out that there are other options that it calls hypermedia. It however does not explain what that other option is, leaving that to come in the first real chapter.

Hypermedia - A Reintroduction

In the first real chapter, we learn what hypermedia is. It's the linking of information so tightly that everything is connected. Hypermedia mixes text, images, video and other formats all into one large mass.

HTML is the largest hypermedia element and building block.

The original web only had anchor tags and this was used to build read only sites to show academic information.

Form tags were the second element added and the first to let a user update resources on a server. This is what opened the gates to building applications on top of html and http.

This was actually a really cool point, I never thought about how magical the form element is and it's really what opens up the web to be more than just documents. even javascript comes after this basic building block exists.

The anchor tag is so common now that the magic has faded but thinking about it for a moment, it is neat to say that clicking a link causes a new page to get loaded. This is similar to how our brains think and how we jump from topic to topic. The whole idea of an anchor is to click it and get a new page to display for the user. The book highlights that this idea of sending back true html is what the system a hypermedia system.

It really is amazing that with just two tags, you can build out the entire web!

The book goes on to show what a SPA version of the anchor and form tag would be and it highlights how javascript takes over all of the process. It needs to handle displaying and updating the screen and sending and getting responses from the server. This means that stuff that the browser is already capable of is being done again by Javascript.

Neither tag interacts with a server via their native hypermedia mechanism. Rather, they become user interface elements that drive local interactions with the in-memory domain model via JavaScript, which is then synchronized with the server using plain data JSON APIs.

The elements of html in a SPA end up being just for display, everything triggers an event that will run some bit of javascript code which will do the actual processing of data.

This is something I've noticed as I'll create buttons and links as components which are ultimately javascript functions rather than being true html elements.

The book says that SPA style applications have taken hold because they are immersive and interactive. This may have been true before but I think nowadays the reason is largely for the developer experience. I know building applications in svelte are now so straightforward and easy that it's actually faster for me to start with svelte than vanilla js and html. If I use a design system, I immediately get components that will just work.

I think HTML might be missing that or it's something I haven't looked hard enough for.

The book then says that HTML hasn't really changed in 30 years. It still has just the anchor and form tag as the only ways of communicating to and from a server. This is one reason why everyone leans on javascript so much. Javascript has a ton of development on it and it has become great to use.

Because HTML has been at a standstill, there are libraries that use javascript to enhance html. The idea is to extend HTML with javascript until browsers catch up and implement things natively. This is like polyfilling new features in javascript.

The idea of hypermedia driven applications is to return html as data and to allow html to communicate to a server. htmx specifically allows any element to become one that can make a request and it adds this ability declaratively. This means that even though it's using javascript, it's really a stopgap until these special attributes become part of the standard. If they ever do.

Why waste all the complexity associated with a heavy JavaScript framework on something as simple as a settings page?

I don't think this is a fair response, if you are already using SPA style techniques in one part of your application, it probably makes more sense to use that everywhere rather than carve out a chunk where you change architectures. The settings page can be made into a hypermedia driven app or a MPA but it could probably just be built the same way as the rest of the application.

Is there only 114 tags in html? That doesn't sound quite right. Indeed there is!

HTML Tag Memory Test

It would probably be a good idea to read all of them just so I'm aware of what's out there. I remember learning the detail tag and being amazed by it. The datalist one is also really good though I hope that some version of combo boxes eventually becomes standard.

Components of a Hypermedia System

A key part of something being hypermedia is that you aren't limited to just reading a document from start to finish.

Regular media like books and newspapers are read only things where you read the information linearly. Hypermedia gets rid of that linearness and let's you jump around. This is more akin to how we think and talk. When we talk to someone, we are never just going on a straight path, often the conversation is jumping and pivoting all over the place.

I wonder if footnotes or quotes make something into more than regular media. They do cause jumps to happen though it is far more limited.

It's only with technology, specifically the web that we get true hypermedia. Now while reading, you can click a link or jump to something completely before coming back. This is what the memex was supposed to be.

HTML is the hypermedia data. HTTP is a protocol that is often used with HTML. Browsers are a hypermedia client and finally a web server is the hypermedia server.

HTML was developed alongside HTTP, however when PUT, PATCH and DELETE were added to HTTP, they were neglected in HTML. Silly mistake as I have seen the PUT, PATCH and DELETE stuff being packed inside of a POST request.

JSON apis will often use http but they will return a status of 200 meaning it was okay and then inside the json, they will send a real status with an error. This always felt silly to me.

I'm not sure I buy that writing and using an HTTP server that sends back html is any easier than using one that sends back json data. The authors mention that hypermedia driven applications don't lock you into use javascript on the backend like json does. They are saying that json data pushes you to use nodejs. I don't think this is true.

Even my own BASIC web server can do HTML or JSON relatively easily.

Though I guess if you do use a big SPA framework, the ability to use node on the backend might be too big to ignore.

More than that though, I think developer experience around using SPA is enticing. If you use a hypermedia approach, you end up writing HTML, CSS and Javascript in one part of you application and then in another folder somewhere you will write the server side code that returns the HTML.

Full stack frameworks have unified the frontend and backend so thoroughly that it is something that is difficult to ignore.

I would love to build some full stack framework for BASIC someday.

A RESTful service must be a client server model with stateless requests. Interesting ideas there. I'm not sure what I thought REST was.

The section on REST seems to require a real understanding of the context and era it was written in. Without that I think http and web tech is so prevalent and infectious that I don't understand why REST is so novel. It's probably that it was the first to really explain these concepts that have now become so commonplace that going back and reading it makes it look unimpressive.

The example of hypermedia data and json data is clear when you see the data itself. Hypermedia data is straight html and so it is data that can be displayed without any processing by the hypermedia client. While the json data needs to be parsed and processed and some knowledge has to be used to figure out what needs to be updated on the UI. REST is the former rather than the latter. REST wants the data to be stateless and also independent of the client. The client shouldn't need to do something to get the data to display.

I quite like that idea. By sending by straight html code, the frontend will be drastiaclly simpler.

Using and sending straight html does get around versioning issues. The data itself has everything the client needs versus json where if there is new functionality or something was deleted, this would require all clients to now change how they handle things.

I don't see how this is a problem though as the frontend is made by the same person doing the backend but this may be specific to me. In a larger team maybe this is crucial difference.

The self descriptive messages is truly a neat idea and using hypermedia as the engine of application state is pretty cool.

The link to Section 4 of the HTML spec is great. It has all the tags and how they should be used.

A Web 1.0 Application

I picked up a side quest at the beginning of this chapter. I wanted to make my SERAPHIM applications closer to how flask looks and this required some re-working and restructuring how my application looks. I was able to do this after some work, though I'm not sure if it was a good idea or that I will even keep this going forward.

The book is going to build a basic contact management application using regular html. The idea is to build a basic application that can later be made into a hypermedia driven application.

The book is going to use python, flask and jinga templates. This maps pretty well with BASIC, SERAPHIM and the BASIC Templating Language.

I've finished building the Contact.app from the book now using my own set of tools. The big thing was that it is a bit cumbersome to use and design and I feel like developer ergonomics of my tools are certainly not good enough yet.

This was also a valuable process to go through as I fixed a bug in my server where the form data wasn't getting set up properly in BASIC.

I started my version of the app to just track people I want to follow on the internet. I created the listing page and I added some entries manually first. I also added a search bar and user query parameters to do the search.

The next page was the new page and this is where I fixed SERAPHIM to handle the form data. This is also where I added errors and validation. Seeing the python code and trying to make it work in BASIC helped to make the pattern more clear and I can now get proper form validation done via BASIC. This is going to be handy to keep as a snippet for the future.

The next page that came up was the view link page. This would display a single link with the data.

The next page was the edit page. This was largely the same as the process for the new page. This could probably be refactored into using the same templates and logic but I left it seperate as the book also kept it seperate.

I added the delete button last and this was the easiest by far.

This covers all the CRUD operations and it taught me how to set up the logic for error handling and displaying messages to the user. I think the flash option in flask is useful and I need to think about implementing that in BASIC. I have an actiondone that I pass when a form is saved and then redirect. Currently I added a close button to the notification which will fix the url but ideally the url is fixed as soon as the page is redirected.

I checked stackoverflow and this seems to be an issue. People use sessions to store this save notifications so that they can get cleaned up URLs. This might be the solution but I don't want to implement sessions quite yet.

There wasn't much I actually learned about hypermedia in this chapter but I think this is the base that the rest of the book is going to enhance.

Extending HTML as Hypermedia

Before I start this chapter, I'm going to pick up another side quest. I want to have a way of automatically compiling and running SERAPHIM. Currently I have to kill the server, compile, then restart the server. This is a bit of a hassle and probably a large source of the friction of writing SERAPHIM applications.

I've finished up the side quest for now. I can now restart my application once the application logic changes. In the future I want to expand this to reload the web page as well when the templates change.

You can read more here.

Now for the actual chapter.

The first thing this chapter points out is that the hypermedia application we've build so far is fully RESTful. It feels a bit clunky because of 2 things, one is that the browser does a full page refresh when doing navigation and the second reason is that we can using anchors and forms to interact with resources.

The first one is the reason why Web 1.0 applications feel less smooth than the modern SPA websites. I think this is probably true. The big difference between old school multi page website and the new SPA is that the SPA feels snappier and smoother to use. It does introduce problems but I think the massive popularity of SPA has made it clear it is worth the trade offs.

One thing I didn't seen mentioned which I think drives SPA adoption is that SPA lets you build components and extend HTML in great ways. This is my reason for using svelte in general. I like that are component libaries I can pull in and I can build parts of an application that completely self contained. This is a superpower to be sure.

In a traditional server side framework like flask, I can see this being more cumbersome and frustrating to deal with.

HTMX is an extension to HTML to combat these two issues that the book says are the reasons why people use SPAs.

The first thing it points out is that there is no inherent reason to why only anchor tags and form tags can trigger HTTP requests. Why can't a button or a div trigger a request. Why can't HTML trigger requests besides just GET and POST.

This is a simple addition to HTML that should have been made already.

The next thing the book brings up is that why are click events the only thing that triggers requests. A form has a button that can be clicked to trigger a GET or a POST. A link can only be clicked to trigger a GET request.

HTML should allow for any event such as mouseover, keyboard events and various other events to trigger HTTP requests.

Next the book brings up that HTML should be allowed to make the full gamut of request, it should be able to do GET and POST but also PUT, PATCH and DELETE.

The last thing the book brings up is that there is no reason why HTTP requests should cause the browser to do a full page refresh. This is largely something the browsers just did and have been doing but there is no reason why HTML and HTTP can't do partial changes to the screen. This last piece is probably the big thing that would make the traditional multi page web applications feel more like a SPA.

As updating HTML to handle these features would require some sort of effort by the committees in charge of HTML, it's easier to build this as a library in javascript. This is exactly what the author of the book has done with HTMX.

HTMX can be installed with just a script tag pointed at the CDN copy of htmx. This is handy to just get started with using it. The great thing is the library allows us to not have to write any javascript code as it's all abstracted away by the library. The goal would be to have the library replaced in the future by development in HTML.

Htmx takes inspiration from the what anchor tags have a href attribute and forms have an action and method attribute to develop the new attributes to do all the things that would make html better.

The first attribute htmx introduces is the set of request attributes.

hx-get
hx-post
hx-put
hx-patch
hx-delete

These attributes will trigger their corresponding HTTP method. These attributes take a url.

The thing to note here is htmx expects the response to be partial html. The page already has most of the markup and so the request only needs to be served by the html it actually needs.

The default behavior of htmx is to get the response and then replace the element that caused the request.

This is not always desirable and this leads to the next attribute.

hx-target

We have an attribute that takes a css selector to where we want the response added into. Here it will continue to do the same thing where it will replace the data inside with the response data.

To control how something gets added to the page we have the next attribute:

hx-swap

Now we can say if the response should replace the inner html, outer html, if it should before the element or after the element. This way we can tune how we want the response incorporated into the page.

These 7 attributes now give us the ability to do all sorts of things to load data from the server, without causing a full page refresh.

The next attribute htmx introduces is:

hx-trigger

This attribute lets you change how the requests are triggered. Traditionally only click events would cause something on the page to happen. With this new attribute we can now trigger on things like mouseenter, mouseleave and keyboard events.

Interestingly form elements will trigger on the change event so when a select changes, it could cause a request to be fired. This sounds useful for something like validation but if you type quickly I can see there being issues if there isn't a debounce.

hx-trigger can also take multiple events so you can trigger on clicks and keyups.

The big thing about this style of development seems to be that the logic is declarative rather than imperative. It feels like html because we are describing behavior we want rather than trying to actually write out how it should behave and all the steps that go into it.

The other thing htmx lets you do is send data when the request type warrants getting extra data.

hx-include

Now you can add an include statement to include data that should be sent with a request.

hx-vals

You can also include specific values by building a JSON structure. This feels a bit hacky as the whole point was to be pure html and now we have JSON. I think I need to see a real example to get why we might want to do this.

Now that any element can trigger requests and they can partially change the page, we need to add a way to update the url and history.

This is done via:

hx-push-url

This attribute can be set to true on htmx elements and this will then update the URL and history.

The problem here is if the page reloads, the page will then show the partial html as that is what the server responds with. The book mentions that this will be dealt with in the future with HTTP headers.

With that the chapter ends. The ideas here are pretty cool and I can see how some of this stuff could be implemented in javascript. I don't feel that jealousy feeling that sometimes comes where I wish I had come up with idea. I think it's because I'm not entirely sold that htmx is a good way of building applications.

I really like how components work in something like svelte but I wonder how much of that is because I lean on component libraries quite a bit.

I was also expecting this chapter to actually cover making changes to the web 1.0 application but it doesn't look to be the case. This chapter was largely just exposing the reader to the new attributes. I'm guessing the next chapter is where we will actually use these attributes.

Htmx Patterns

This chapter of the book strangely introduces a new attribute that does quite a bit. It makes sense as it should be introduced after the core of htmx is explained but I think it would have fit better in the previous chapter.

hx-boost

This tag transform a regular anchor tag that does a page refresh into an AJAX request that fetches the data and swaps it for the body. This attribute handles setting the history properly and parsing our the parts of the response that it needs to load in. This seems to be a fair amount magic.

For instance I'm guessing that hx-boost will check the head for new scripts and styles to be loaded into the current page. I wonder if it also removes things if the new page it is getting is wildly different.

The book says that the head of the new page is skipped as the old page will have that code still and alot of time is spent processing that. The idea is by swaping the body of the new page for the old page, the navigation experience will be smoother.

hx-boost is also an attribute that can be inherited, this means that you can place it on the body tag to have every anchor and form become boosted. This would mean that the application would feel more like a SPA than a traditional website. This however would also affect links like PDFs which you may not want. This is why hx-boost is a boolean so you can place it on the body and then local links can be made unboosted.

This attribute seems to be doing quite a bit which I'm bit hesitant to use but it looks useful.

The first change to the app we're building in this book to add htmx is to add the library and then make the body boosted.

Then I could see in the network tab that the links were now being made into just network calls rather than full page refreshes.

The next major thing the book covers is making the Delete button truly a hypermedia control.

The original design was to use a form with a delete endpoint and set the method to POST. Now with htmx, this can be changed to just a button that does a DELETE request.

   <button hx-delete="/link/{{ITEM.ID}}" hx-target="body" hx-push-url="true" hx-confirm="Are you sure?">
      Delete
   </button>

Here we set the target so that when the Delete button is pressed, the response replaces the entire body. This mimics what the original did where it was a redirect.

On the server, this is still just a regular redirect. Htmx handles taking the redirect and massaging into the current page.

We have a the push-url attribute here so that the response from the delete updates the URL. Otherwise the url would have stayed on the edit page but the body would have been showing the main links page.

Finally, there is a new attribute here that let's you confirm a hypermedia request before it goes through. This is handy for destructive elements like deletes.

This is quite nice to see in action.

The next example the book covers is converting a regular input box into a hypermedia control.

   <input id="name" type="text" name="name" value="{{LINK<1,1>}}"
      hx-get="/link/name"
      hx-target="next .error"
      hx-trigger="change, keyup delay:200ms changed"
   />
   <span class="error">
      {{ ERRORS<1> }}
   </span>

There's alot going on in the above code but it's a pretty good pattern.

We want to add validation to the input so that we can do a check to see if the name has already been used previously. The check should be as the user types. This is something users have come to expect and makes for a good UI. Instead of having to submit the form to get validation errors, now they can get it as early as possible.

The first step is to add the hx-get attribute. By default inputs trigger the request on change which requires a blur. We want the endpoint to return a string for the errors and if there are no errors it should be blank. This response is populated in the hx-target. Here we use the next keyword to say that we are populating the next error class.

We also want to execute the request on change but we also want to do it when the user types. We update the hx-trigger to contain both the change and keyup events.

However keyup will track all keyboard events, not just those that cause changed to the text, this means that things like arrow keys will also fire the request to do the name validation. We can update the trigger to contain the keyword changed so that it only executes requests when the input value changes.

The final thing to note is that the trigger will currently run everytime the user types, this is useful but we often want to batch these changes before sending it, we don't need to send every keypress, we can wait for the user to pause before sending the data for validation. This is where the delay keyword comes in.

We now have a way of doing real time validation using hypermedia controls.

The most complex thing here seems to be the trigger as there seem to be quite a few modifiers that you can use. It looks like the structure of a trigger is that it is a comma delimited list with modifiers that go after the event.

Just for fun here is what the validation routine looks like:

*********************  S U B R O U T I N E  *********************
*
* /link/name
*
GET.LINK.NAME:NULL
*
   LOCATE('name',REQUEST(REQUEST.QUERY.ATTRIBUTE)<1>,1;QUERY.POS) ELSE ACTION.DONE = ''
   NAME = REQUEST(REQUEST.QUERY.ATTRIBUTE)<2,QUERY.POS>
   NAME = CHANGE(NAME,'%20',' ')
*
   ERRORS = ''
*
   IF NAME = '' THEN
      ERRORS<1> = 'Invalid name.'
   END
*
   COMMAND = 'SELECT WAVE-FILE WITH NAME = "' : TRIM(NAME) : '"'
   PRINT COMMAND
*
   EXECUTE COMMAND CAPTURING RESULTS
*
   READNEXT ANYTHING THEN
      PRINT ANYTHING
      ERRORS<1> = 'Name already exists'
   END
*
   RESPONSE(RESPONSE.STATUS.ATTRIBUTE) = 200
   RESPONSE(RESPONSE.CONTENT.ATTRIBUTE) = ERRORS
*
   RETURN
*

As you can see it's a very simple subroutine. However this does mean that each validation requires a large chunk of code that is probably duplicated. There is probably a cleaner abstraction for this.

I could also see these kinds of routes getting put into a /validate/ route and then them being put into a VALIDATIONS subroutine. I think that might be the best way to start building out a variety of server side validations.

This however does mean that there is validation happening in two places, onces for the real time validation and then again for the save routines.

The book also covers adding paging using htmx. This is a relatively straightforward implementation where most of the logic will be tied to the actual paging process. In SPAs, we can send over tons of data and paginate in the frontend but for performance, you will probably want to paginate on the server. This is going to be the default for a hypermedia application.

The book covers paginating use next and previous buttons. It also covers a click to load option. The click to load version can then be extended to be an infinite scroll as htmx adds a revealed event that it can listen for. This way while scrolling if a certain div or span comes into view, it will trigger the revealed event which in turn can trigger a request to fetch data from the server and to swap it into the page.

This pagination stuff is useful. It might be useful to implement right now but I think there are more important things I want to first read and add before I come back to the main page to add pagination.

I ended up doing some pagination stuff just so I had the basics working. It was straightforward and like I thought it wasn't really htmx related and more so just regular pagination.

The most interesting thing was that at the end of the chapter, the book says that we shouldn't use modals. I was actually thinking of moving the edit form into a modal as switching pages seems like it's pointless when there isn't that much information to update. However it looks like modals are not simple or straightforward. I'll still want to be able to display information in a modal and having a formin a modal is too useful.

I think htmx is looking pretty good and the fact that there is only a few attributes to learn is great. It would be nice however to be able to write my server side logic and my template in one place. Currently I have to edit two files to wire things up. This is more of a limitation of the templating language.

I do have some designs for making my templating language more akin to PHP but that's a way down the line.

I used the validation logic to update my search bar so that I could get results as I type. This worked out pretty well. I can see some issues with code duplication however. I can see the templates being easily composed but having to be careful around them. The BASIC side could be simplified by moving things into subroutine calls so I don't duplicate code. I'm sure this issue exists for SPAs as well so this isn't really a negative. Code duplication and abstractions are neverending problem.

Overall I'm pretty happy with how this chapter turned out.

More Htmx Patterns

I jumped ahead...I implemented the search but the book is going to cover a better implementation now. At least now I can compare what I had done with my limited knowledge with how it should be done.

   <input id="search" type="search" name="q" value="{{QUERY}}" placeholder="Search" 
                hx-get="/"
                hx-trigger="search, keyup changed delay:200ms"
                hx-target="tbody"
                hx-push-url="true"
                hx-indicator="#spinner"
                />

The above is almost identical to what I had written naively which means that htmx has some good patterns and that even the basics will just work.

The difference in the front is that the get request still happens to the same one that the from submits too. This is a nice feature but I don't think it's necessary. I could have the input go to a specific endpoint to get data.

The difference is on the backend:

*********************  S U B R O U T I N E  *********************
*
* GET /
*
GET.INDEX:NULL
*
   LOCATE('HX-Trigger',REQUEST(REQUEST.HEADERS.ATTRIBUTE)<1>,1;POS) THEN
      HX.TRIGGER = REQUEST(REQUEST.HEADERS.ATTRIBUTE)<2,POS>
   END ELSE HX.TRIGGER = ''
*
   IF HX.TRIGGER = 'search' THEN
      GOSUB GET.SEARCH
      RETURN
   END
*
   LOCATE('actiondone',REQUEST(REQUEST.QUERY.ATTRIBUTE)<1>,1;QUERY.POS) THEN
      ACTION.DONE = REQUEST(REQUEST.QUERY.ATTRIBUTE)<2,QUERY.POS>
   END ELSE ACTION.DONE = ''
*

Here we check the HX-Trigger header and if there is one we check to see if it's search. If it is, then we can just run the search process and return the rows that are relevant instead of the full html.

The book also gives an example of refactoring the templates to be a bit more composable so that seems to be the process that I should follow.

Overall, my own way and the way that the book proposes are fundementally the same, the HTTP headers logic is going to be handy but it might be better to not use it. I'm not sure if the headers are safe or if there going to introduce some complexity that one needs to hunt down to make sure they know what is going on.

A straight request to a new search endpoint to get rows in my eyes feels cleaner.

The next thing the book covers is lazy loading. This mixes a few concepts, it mixes a specific endpoint to do an expensive request and then uses the revealed event to only execute the request when something comes into view.

            <p>
                <a href="/link/new">Add Link</a>
                <span hx-get="/links/count" hx-trigger="revealed">
                    <img id="spinner" class="htmx-indicator" src="https://i.redd.it/inb7xkog7y131.gif" style="height: 25px;" alt="Request in flight" />
                </span>
            </p>

These are some useful features and things that I've implemented in SPAs before and I don't think it's ever been easier than this. The way to do lazy loading being purely via attributes that I've already used is magical.

This makes me wish to see these attributes made standard. I think that would really make everything so much easier to develop.

The book also goes into adding a delete to the listing page so that you can do a delete there. This then leads to having the ability to delete multiple items. This required a small change in my SERAPHIM server to allow for POST data to be sent for all requests and not just POST.

If SERAPHIM had the same problem as HTML where it required a committee to make decisions before a change can be made, I'd be stuck in the position of smuggling methods in a POST request, I can see how and why HTML has languished. Hopefully it can get some of these really cool features some day.

I'm starting to understand htmx but it's going to take a bigger project to really hammer it in I think.

A Dynamic Archive UI

This chapter starts by explaining what the goal is going to be. Unlike the previous chapters, this one is going to focus on a single new function. We want to export the list of links out to a file and make it downloadable. The big thing is that the process of generating the archive can take some time so it needs to be an asynchronous job.

This means that the job is added to a queue and the web server actually checks the job's status to know how far along it is.

In BASIC this would be a JOB or QUEUE file where we can monitor it by looking at a STATUS. This is a feature I've been wanted to build out for awhile and it looks like it may be time to do as a sidequest here.

For now I'm going to fake it but I think this could be a fun project.

This has been probably my favourite chapter so far because it feels the most useful and it has an extremely cool reasoning for why htmx works the way it does.

The first part is the frontend template:

<div id="export-ui" hx-target="this" hx-swap="outerHTML">
    {{ IF STATUS = 'RUNNING' THEN }}
        <div hx-post="/links/export" hx-trigger="load delay:500ms">
            Creating export: {{ STATUS }}
            <div class="progress">
                <div id="export-progress" class="progress-bar" role="progressbar"
                    aria-valuenow="{{ PROGRESS }}"
                    style="width: {{ PROGRESS }}%"
                    >
                </div>
            </div>
        </div>
        
    {{ END ELSE IF STATUS = 'COMPLETE' THEN }}
        <a hx-boost="false" href="links/export/download" _="on load click() me">
            Download
        </a>
        <button hx-delete="/links/export">Clear Download</button>
        
    {{ END ELSE }}
        <button hx-post="/links/export">
            Export
        </button>
    {{ END }}
    
    <style>
        .progress {
            height: 20px;
            margin-bottom: 20px;
            overflow: hidden;
            background-color: #f5f5f5;
            border-radius: 4px;
            box-shadow: inset 0 1px 2px rgba(0,0,0,.1);
        }
        
        .progress-bar {
            float: left;
            width: 0%;
            height: 100%;
            font-size: 12px;
            line-height: 20px;
            color: #fff;
            text-align: center;
            background-color: #337ab7;
            box-shadow: inset 0 -1px 0 rgba(0,0,0,.15);
            transition: width .6s ease;
        }
    </style>
</div>

This code has 3 states, the first state is the Export button which appears when the user hasn't dont anything yet. When the button is clicked, the component enters the RUNNING state where the progress bar is displayed. Htmx allows for polling triggers to run as well so you can poll a server for a response and swap it in.

I'm not sure how htmx is working here to stop requesting. The docs mention that a header is sent when something is finished but I'm not currently sending that but the requests do stop when the progress bar hits 100. I think this might be some magic.

The cool thing here is htmx replaces the div on each request. This means that CSS transitions don't kick in normally as they are getting applied each time. Htmx checks to see if the content it is loading has any ids already present on the page. If it is, the new content will get the old ids added and then after a moment they will be updated with the new information. This way CSS transitions will happen properly. This is what gives the progress bar a smoother feel.

This bit of logic is quite cool and I love the cleverness.

Here is the backend code, I fudged the progress bar by having the progress change everytime the endpoint is hit. This way I could skip implementing a real queue system.

*********************  S U B R O U T I N E  *********************
*
POST.EXPORT.LINKS:NULL
*
   STATUS = 'RUNNING'
   READ PROGRESS FROM CONTROL.FILE, 'PROGRESS' ELSE PROGRESS = 0
*
   IF PROGRESS = 100 THEN
      STATUS = 'COMPLETE'
      PROGRESS = 0
*
   END ELSE
      PROGRESS = PROGRESS + 20
   END
*
   WRITE PROGRESS ON CONTROL.FILE, 'PROGRESS'
*
   CALL MAP.SET(MAT ENV,ENV.SIZE,'STATUS',STATUS)
   CALL MAP.SET(MAT ENV,ENV.SIZE,'PROGRESS',PROGRESS)
*
   READ TEMPLATE FROM HTML.TEMPLATE.FILE,'WAVE-EXPORT.HTML' ELSE TEMPLATE = 'Invalid Template'
*
   CALL RENDER(MAT ENV,ENV.SIZE,TEMPLATE,RESULT)
*
   RESPONSE(RESPONSE.STATUS.ATTRIBUTE) = 200
   RESPONSE(RESPONSE.CONTENT.ATTRIBUTE) = RESULT
*
   RETURN
*
*********************  S U B R O U T I N E  *********************
*
DELETE.EXPORT.LINKS:NULL
*
   STATUS = ''
   PROGRESS = 0
*
   WRITE PROGRESS ON CONTROL.FILE, 'PROGRESS'
*
   CALL MAP.SET(MAT ENV,ENV.SIZE,'STATUS',STATUS)
   CALL MAP.SET(MAT ENV,ENV.SIZE,'PROGRESS',PROGRESS)
*
   READ TEMPLATE FROM HTML.TEMPLATE.FILE,'WAVE-EXPORT.HTML' ELSE TEMPLATE = 'Invalid Template'
*
   CALL RENDER(MAT ENV,ENV.SIZE,TEMPLATE,RESULT)
*
   RESPONSE(RESPONSE.STATUS.ATTRIBUTE) = 200
   RESPONSE(RESPONSE.CONTENT.ATTRIBUTE) = RESULT
*
   RETURN
*
*********************  S U B R O U T I N E  *********************
*
GET.EXPORT.LINKS:NULL
*
   LINES = ''
   SELECT WAVE.FILE
*
   LOOP
      READNEXT ITEM.ID ELSE ITEM.ID = ''
*
   UNTIL ITEM.ID = '' DO
      READ WAVE.MATRIX FROM WAVE.FILE, ITEM.ID THEN
         LINES<-1> = LOWER(WAVE.MATRIX)
      END
   REPEAT
*
   CONVERT @AM TO CHAR(10) IN LINES
   CONVERT @VM TO ',' IN LINES
*
   RESPONSE(RESPONSE.STATUS.ATTRIBUTE) = 200
   RESPONSE(RESPONSE.CONTENT.ATTRIBUTE) = LINES
   RESPONSE(RESPONSE.CONTENT.TYPE.ATTRIBUTE) = 'text/csv'
*
   RETURN
*

The final thing to note is from the frontend:

        <a hx-boost="false" href="links/export/download" _="on load click() me">
            Download
        </a>

This uses _hyperscript, another library by the author. I had seen examples before but I never actually used it yet. I decided to use it here as the book suggests and it feels pretty good to use.

I'm deciding now to use _hyperscript as my scripting language for this project that I'm working on.

The export template feels very much like a component but I know the style tags are leaking and nothing is really localized. There is probably something I could do in BASIC to get a real component set up. Possibly something like svelte where I have a compiler that takes my templates and makes them into real components with javascript. That would be a huge project probably.

Tricks of the Htmx Masters

These tricks look to be largely the advanced options for the various attributes. You can use the basics but to get fancy requires learning the htmx language. I think it does look lik a language because you have events you can use and then there is a special syntax to do things to those events.

Interestingly the use of htmx trigger headers and listening to those events I think might let you build a chat application relatively easily with htmx. This would be true even in my single threaded web server. The core of it is still just long polling but I think it could all be done without any actual javascript being written.

This could be a fun project as well, a chat application with htmx.

A cool thing is that the server has access to some htmx abilities so the server could update the url itself rather than the htmx element on the page. You can also send a retarget which seems interesting.

Alot of these tricks I think will be better understand with a real application but I doubt the book is going to do that unfortunately.

Currently htmx does nothing when a 404 is returned but by modifying the beforeswap event you can log 404 errors. This seems extremely useful for debugging as currently I need to check the console or network tab or the server logs to see errors.

You can also send back multiple parts of the page in one response by using hx-swap-oob attribute. This will update the old content with a matching id with the new content.

The htmx configuration is coolly done via the meta tag. I was expecting a javascript function but the authors have taken expanding html so deeply that the configuration is in html. I love that energy.

This chapter was mostly just an overview of the advanced usage. It's good to know and hopefully I can remember some of these when I get to anything complex.

Client Side Scripting

This chapter and the next can probably be skipped as they basically are not really tied to htmx. This chapter covers examples of using javascript for some functionality.

Strangely, the book covers vanilla javascript, alpinejs and hyperscript. It showcases 3 ways of adding interactivity which I think is interesting but I'd have prefered them to just showcase hyperscript. I think it is the most interesting of the three and personally I think that would have made for a better read.

The first function the book covers it having a menu for the edit/view/delete options on the listing page. I wrote all the examples in hyperscript so you can see that here.

            <div>
                <button type="button"  _="on click toggle [@hidden] on next <ul/>">Options</button>
                <ul hidden>
                    <li><a href="/link/{{LINK<1,1>}}/edit">Edit</a></li>
                    <li><a href="/link/{{LINK<1,1>}}">View</a></li>
                    <li>
                        <a href="#"
                            hx-delete="/link/{{LINK<1,1>}}"
                            hx-confirm="Are you sure?"
                            hx-target="closest tr"
                            hx-swap="outerHTML swap:1s"
                            >
                            Delete
                        </a>
                    </li>
                </ul>
            </div>

The core of it is that I now have a button that has an underscore that hyperscript will process.

The syntax is pretty funny looking but it does feel quite natural. I actually quite like the idea of it. On clicking the button, toggle the hidden attribute on the next ul tag.

This is actually quite cute.

I could probably use some css transitions to get this to be a prettier effect but as a basic idea it works.

The next thing the book covers is adding a toolbar for selecting all the items for deletion and only showing the delete button when there is something selected. This show cases how easy it is to generate events with hyperscript. I've wanted to use events before but it always felt cumbersome, hyperscript however makes this unbelievably easy.


                <span id="toolbar" hidden
                    _="
                    on selectionChanged
                        if length of <input[name='selected']:checked/> in #main-table > 0
                            remove @hidden from me
                        else
                            add @hidden to me
                    end
                    ">
                    <button
                        hx-delete="/links"
                        hx-confirm="Are you sure you want delete these links?"
                        hx-target="body"
                        >
                        Delete Selected
                    </button>
                </span>

The tool bar listens for selectionChanged events which will then trigger the if statement. If there is something selected, the toolbar will become visible, otherwise it will be hidden.

The sending side:

        <td>
            <input type="checkbox" name="selected" value="{{LINK<1,1>}}"
                _="on click send selectionChanged to #toolbar"
            >
        </td>

When the checkbox is selected, it will send the selectionChanged event to the toolbar.

Beautifully simple!

The last thing the book covers is adding a shortcut to focus on the search bar:

                <input id="search" type="search" name="q" value="{{QUERY}}" placeholder="Search"
                hx-get="/"
                hx-trigger="search, keyup changed delay:200ms"
                hx-target="tbody"
                hx-push-url="true"
                hx-indicator="#spinner"
                _="on keydown[altKey and code is 'KeyA'] from window focus() me"
                />

We have a little bit of hyperscript that adds a great little shortcut to focus on the search bar.

I'm actually blown away by how little code went into adding some useful interactiveness to the application. I think a book on hyperscript could be quite fun as well and I actually want to write more hyperscript now. I'm currently thinking about writing some hyperscript for the alpine components.

The drawbacks to hyperscript is that because it's so niche, there isn't much help available so I can't see too many examples. It also is difficult to debug but that may be because I'm still not familiar with it.

Definitely learning hyperscript.

JSON Data APIs

This chapter focuses on something I think is completely unrelated to htmx. This chapter highlights how you can build JSON endpoints alongside your hypermedia endpoints. This seems to be self-evident but good to say it out loud.

I didn't follow this chapter at all as building out the JSON data end points felt trivial.

Hyperview: A Mobile Hypermedia

Hyperview is a mobile version of htmx. The authors have built an opensource hypermedia client they call Hyperview. You can take this and modify it to work with your backend that returns what they call HXML. This is a custom HTML specifically made for Hyperview.

This seems to be an abstraction over something React Native. Hyperview is actually a React Native application that was built to function similar to how a browser functions.

It's an interesting idea. I'm not keen on learning mobile so I'm going to skip this for now. In the future I may come back to using this as it may be easier to use than react native.

Conclusion

A quick word about how web development is so focused on new that it tends to ignore things that came before. In this case hypermedia is treated as legacy but with some small modifications the ideas of hypermedia are as useful as they ever were.

I buy that especially as someone working in legacy systems.