Building a slick comparison tool with htmx

Lazarus:

So I wanted to record something about a project I worked on, last week and, ended up using h t m x for and I posted something about it on Twitter. I'll include the link to that post here, so you can see what I'm talking about here. But basically it was, you know, I think it's an interesting sort of use case for, like these sort of HTMX hypermedia controls. Basically it's a bill text comparison tool, and bills meaning legislation. So you take 2 2 different bills and you compare the text between them to see, okay, you know, what's changed, that can be meaningful.

Lazarus:

This is sort of part of the industry that I work in, normally, which is kind of legislative data at the state level. So the way this worked, this tool that I added, I added this to an existing site. The way this worked is there's 2 different forms, and I made each form look like a little document, like a little piece of bill text. And each one has an input that's a lookup, and you set your text, you you choose which document you wanna look at, document 1, document 2, and then underneath is a red line, green lines, diff document. So this is an old app, first of all, that I'm adding this to.

Lazarus:

It's actually Laravel 5. So they're now on like 11 or something like that. So just for some context, you know, this is not like just kind of going in and and, you know, using the latest the latest greatest stuff. The site had been originally built using Vue, Vue JS, which I deeply regret. And a few years ago I had sort of mostly given up because it's Laravel 5 and like, you know, to bring it up to Laravel 11 would be a big project on its own that I don't know if I want to try to try to do that yet.

Lazarus:

And so I'd kind of given up on adding new fancy features to it. And fancy, like I think you know what I mean by fancy. It's like these kind of really nice user experiences. You can get some basic stuff with it just kind of multi page app like normal form submission and all this stuff. That stuff's fine, but adding sort of these fancy features, making it kind of work in a nice, low nice way.

Lazarus:

I'd kind of abandoned that because I didn't want to use Vue anymore for stuff like that. So, enter, you know, HTMLX, and this is kind of what I've been doing with a lot of my project. This is a perfect use case for this kind of server driven hypermedia setup, this type of of project. It's, you know, a group collaboration. You have a team, everybody logs in, they have their specific data, they have to share data, so you need it to be sort of server driven.

Lazarus:

Most of the stuff that happens, you need sort of immediate updates, you're pulling from the server, you're getting the latest stuff. We have 100 of thousands of pieces of legislation, so they need to be able to compare 2 pieces of legislation from any year. It's all on the server. So this is a good use case for a server, you know, server driven background. So how does HTMX come into it?

Lazarus:

The basic idea is that we have these 2 lookups up at the top. Look like little bill documents. The whole setup for this new page, this new feature is 3 routes, 3 partials, 3 HTML snippets, however you want to sort of say that. There's the main page, which kind of loads everything. There's the form, a snippet that contains the form that has the 2 documents, as well as, the button to generate.

Lazarus:

And then there's the actual lookup. So when you type something in, that lookup that's returned. So that's it. Just 3 different partials, 3 different pieces of HTML. The form is the 2 pieces of built, you know, the the the container that has the the build text lookup, the IDs that end up when you do a lookup, it puts in the the bill along with some hidden info, you know, just to so that you know secretly which the actual ID is.

Lazarus:

You know, it shows the user the name of the bill, but behind the scenes you have to use the bill ID, stuff like that, just to make sure that it's getting the right stuff. So it has a little bit of hidden info in the form. The lookups have an h x trigger on the key up, so there's not actually that much HTMLX in this setup. It doesn't need a lot. For the most part it's just, you know, HTML.

Lazarus:

I use Laravel, so blade. It's just kind of showing we have 3 different blade files, the main one, and then we include the form, and then when you do the search on each input, there's an HX trigger on key up, which has, you know, some debounce 500 millisecond delay, 500 milliseconds. We have an HX get that goes to the bills comparison lookup, and we have an HX include, which is closest form. So it just takes everything that's part of that form and sends it along with it. And then we have the HX target.

Lazarus:

So that's where the lookup is going to go, which in this case is a data list, just a built in browser data list, not some fancy drop down. This is just using what's there with the browser. So they submit the whole form including both lookups every time they do a lookup. And there is a reason for this, which I'll get to in a minute. So when they do the lookup it matches many items.

Lazarus:

So we show a data if it matches many items we show a data list. So they can choose between a list of, you know, let's say 10 bills, I think I have a limit on how many it shows at once. So they see the data list, they select it, and if there's only one selected or if they click 1, then we show that item is selected and we add a clear button so they can clear it out. But now we have, you know, this document is chosen, and you can clear it out if you want to. If both of these inputs have only one result, so the one on the left and the one on the right, then we're sort of ready to show a generate comparison button.

Lazarus:

So the way this works is you have the lookup. Each time you do a lookup, it's also sending the other lookup. It's sending the other, you know, piece of the form, the other text document. So if both text documents are selected and there's only one option for each one, then it shows you the generate comparison button. So that just kind of makes sure that we're not showing the generate comparison if we can't do it yet.

Lazarus:

So this is part of that sort of hypermedia idea of like we're giving them right in the HTML the controls they need. If they don't have both selected we still show a generate comparison button, but it doesn't do anything. It just looks the same except it's disabled and it's grayed out. Once they have both selected all of a sudden that button is replaced and now it's blue, you know, and it's you can click it and generate the comparison. So it looks like a button.

Lazarus:

It could be a form submit and we would submit the form and it would have both and then it would set the target to down below, right? That would be one way to do it. So actually it's not what I ended up doing though. Ended up saying, you know what, this generate could be a link. So I just make it a regular link with the HREF that contains the 2 IDs.

Lazarus:

So, you know, bill 1 equals the ID, bill 2 equals the ID, and that's just literally just an a tag, like just a link that, you know, we're we're creating that from the lookup, we know that we have each bill, We're then creating that button using HTMLX, we send to the server as part of our lookup, we get back the button, that button now is just a link that has our 2 bill IDs to run the comparison, which is just going to reload the same page, but with those bill IDs sent, so that it's now just a regular page that you can navigate to and from. And it has up in the URL bar just the specific info you need. So this is very important to me that users are gonna be able to use the back button just like normal. They're gonna be able to send the links to their team if they want to say like, oh, check out this comparison I just ran. Right?

Lazarus:

They can just copy the URL up at the top and send it. So this is like one of the really joys to me using HTMX. And the reason I'm kind of putting this out there is this kind of I just had a really good experience, building this, and it wasn't exactly easy because there's a lot of different ways to do this, and I'm sure people, you know, someone else might have find a very different way. Even myself on a different day might have found a different way. But I was really happy with the way this came out.

Lazarus:

The experience for the user is really nice. We also sort of stayed really close to the browser. So by default, you know, everything like you can you you sort of can use it just as a normal page. You can I'll be able to link to it from anywhere. It's because it's just using that, like, ultimately the u the in the h ref up at the top, we're just sending URL parameters.

Lazarus:

So we can just like link that from anywhere else on the site. It's gonna bring us to that page with everything filled in the right way. And there isn't all that much h t m x here. The one thing I haven't mentioned is how the lookups fill that button and, you know, they do 2 things. When you type in and do a lookup, it's creating that data list.

Lazarus:

So your target for each lookup is the data list. That's where it's putting that. But with that response, I'm also using HX swap o o b to fill in the button if it needs to be updated. So HX swap o o b lets you set another ID and send HTML to that ID. So what I'm doing is we have a spot for the button at the bottom to generate.

Lazarus:

If our lookup now contains both bills, and only one option for each bill. So basically, if the lookup is complete, both have been selected. It's going to now send using HX swap o o b that button as well. You know, by default it's just going it's just going to the lookup, the data list. So our lookup is kind of serving 2 purposes.

Lazarus:

It's doing a lookup and returning the response of like here's a bunch of items, or it's updating that button so that we can now say, okay, our lookup is basically over. Now you have access to this button where you can click it and actually generate, the comparison. So that's pretty much it. You know, it's just these three files, main dot blade dot PHP, form dot blade dot PHP, and then lookup dot blade dot PHP. And there's not a ton of HTMX in it, but the user experience is really nice.

Lazarus:

And of course, you know, I worked pretty hard to make it look nice also, which makes a big difference. And there's even more sort of, you know, I could do. One more thing I'll add, I did add one more little thing. The final comparison, you see like bill 1 on the left, bill 2 on the right up at the top to see what you're doing. But maybe, you know, this is like red line green line showing the differences.

Lazarus:

So red means it was removed, green means it was added based on the 2 different bills. So what if you want to swap that direction? You know, what if you want to consider 1 bill your base and the other one your changes, and then you say actually this should be the other way around. So I added a little button that's just swapping the 2, and all that is is just a link with the H ref equals, and then it goes to the same page, so bill 1 equals, and then we swap the 2 IDs. So we we take the ID of bill 2, and we put it, you know, bill 1 equals this, bill 2 equals the old bill 1 ID.

Lazarus:

So it's just swapping those 2, it's just a regular link, but I did add an HX boost to it so that when you click that regular link to swap them, even though it is really going to, you know, a new link, HX boost will do the thing where it doesn't reload the whole page. It just, you know, goes and updates, just reloads the body from there. By default that HX boost, one of the one of the issues with it is that it will scroll to the top by default because it's you know, it tries to act like a regular link, which would scroll to the top. Now we don't want to do that in this case because we're looking at the comparison. We just wanna click the swap, and we want everything to stay in the same place, so no scrolling.

Lazarus:

So luckily, I came across, you know, there isn't a default. There should be a default where you put like HX boost equals true, and like, I don't know, add some like scrollable no or something like that. That would be sweet. But there isn't something like that. So shout out to a Reddit user.

Lazarus:

I have his name here. Thoram Thoram. I don't know. But shout out to Thoram. I'll include a link, that it's a little just a little trick that he found.

Lazarus:

If you add a hash, like a little pound symbol to the end of your your URL that you're putting for the, you know, HX boost equals true, but the URL that goes to the h ref, just put a little pound on the end of it. As if you were doing an ID and scrolling to a particular ID, but you you don't you don't put any specific ID, you just put the pound. That's gonna make it so that HX boost does not scroll to the top after your click, which is which is exactly what you want in this case. It's a really nice user experience. And I put, you know, I put that little video up.

Lazarus:

I put a video up on Twitter of this whole thing. So, you know, if none of this is making sense, it might be nice to kinda you could check that out. I'll include the link. It was a very popular feature. I it went to, it was shown at a it was demoed at a conference, with a bunch of people who are customers, and they were very happy about it.

Lazarus:

And it's just a little bit of HTMLX. This is all a server rendered thing. Looks nice, works fast. It's fast. It's reliable, and I can link to it from anywhere else on the site.

Lazarus:

And it just sort of fills in the build text form values and opens the page if you link to it from somewhere else. So, you know, it I have some code in there to just if you pass in the right stuff, it will make sure that everything is filled in. So that you can then go and you can make changes and look up other bills and and do it all ever else you need to. But the overall experience was really positive and I just kinda wanted to to put that out there as a, you know, a little example of the type of work, that I'm doing with older code bases and kind of the success that, that's been kind of driving my interest, in in HTMX. And I I think shows some of the power.

Building a slick comparison tool with htmx
Broadcast by