back to index

How HTMX is changing the web, with Carson Gross


Whisper Transcript | Transcript Only Page

00:00:00.640 | Hi there, this is Jeremy Howard from Answer AI. And I am here
00:00:05.960 | with Carson from HTMX. And Carson's probably not going to
00:00:13.240 | like this if I introduce him in two glowing terms, because he's
00:00:16.440 | a very humble man, but I can't help it. There's just a few
00:00:18.880 | people in the world, very few people in the world who I
00:00:22.080 | assign the epithet genius to. And Carson is one of them. He's
00:00:28.440 | one of the very few. He looks and sounds like a little league
00:00:34.480 | baseball coach. And that's because he is, I'm sure he's a
00:00:36.920 | very good one as well. But that is not the genius that I wanted
00:00:39.680 | to talk about today. I wanted to talk about HTMX. So Carson,
00:00:43.200 | welcome.
00:00:43.720 | Thank you. I appreciate that. You know, I appreciate you
00:00:48.040 | saying that. But no, I can't agree with that. I do. I do look
00:00:52.320 | like a baseball coach.
00:00:54.960 | Are you a good one? Do your little league say that you do a
00:00:57.880 | good job?
00:00:58.400 | I you know, baseball makes people crazy. So I have a lot of
00:01:04.120 | people that like me and then a couple of people that don't. And
00:01:07.160 | so I'll leave it at that.
00:01:08.520 | I love it. And I feel like I know about your your other life.
00:01:12.640 | Yeah, it is definitely pretty funny. Sometimes I'll just be
00:01:17.480 | like, man, this is very different than my online.
00:01:21.680 | That's great. So
00:01:22.800 | well, something we both share in common is that we live a long
00:01:26.200 | way away from everybody else doing what we're doing. And we
00:01:29.640 | do things in a really different way to everybody else. So that's
00:01:33.160 | where I wanted to start, you know, HTMX is like, the most
00:01:38.840 | misunderstood piece of technology I've come across in
00:01:41.520 | my God, how long I've been coding for 40 years of coding.
00:01:45.280 | So I wanted to help people understand it. And sure, I think
00:01:51.000 | the best way for people to understand it would be to read
00:01:53.720 | your damn book. So I'm just going to share like that on the
00:01:56.720 | screen. But that was short for a pretty short interview. So
00:02:00.400 | here's your damn book. I'm not just you, you and Adam and
00:02:05.520 | Dennis. hypermedia.systems called a main name. And the
00:02:09.560 | whole thing's free for God's sake. What are you trying to do?
00:02:12.720 | You're like, yeah, you're not gonna actually this right now.
00:02:18.600 | Books are not a good way to make much money in general. I know.
00:02:22.800 | Yeah, you know. And even worse, I uploaded the EPUB lib gen. So
00:02:30.280 | if people, if people want,
00:02:32.240 | if they don't want to pirate your book, they can they want to
00:02:35.280 | pirate, they can do so with my blessing. No, but they're not
00:02:38.520 | going to do that now. Because part of getting stuff off lib
00:02:41.080 | gen is like, you know, sticking it to the man. And if you're
00:02:43.760 | like uploading it there yourself, it's like, why even
00:02:46.480 | bother? Yeah, exactly. Well, you know, I figured someone was
00:02:49.920 | gonna do it anyway. So might as well be made. So yeah, but yeah,
00:02:54.880 | there's a hardcover that's, if you really if you want to spend
00:02:57.640 | some money on a physical artifact, the hardcover, it's
00:02:59.720 | pricey. And my understanding is it's hard to get in Australia.
00:03:03.440 | But it, it has a really cool cover that was done by us
00:03:08.720 | graphics. Really, really happy with that. And then we just
00:03:12.360 | released the soft cover to Yes, which on Lulu with a beautiful
00:03:17.480 | song. And that's, yeah, that's got a pixel art cover that we're
00:03:22.720 | super happy with. It's we there was a, a pixel artist on fiber
00:03:28.840 | named ash. And he did an unbelievable job with it. So
00:03:32.520 | super happy with that. Yeah, I love it. And one of the few
00:03:37.200 | pieces of software were released recently that was initially
00:03:40.960 | available only on floppy disk.
00:03:43.320 | Yeah. Yeah, we did that for a couple weeks. We had a we have
00:03:48.080 | floppy disks. I don't think they're available on the store
00:03:51.120 | anymore. But you can buy them for a little bit. So yeah, we
00:03:55.280 | have some fun. So it's all have some fun.
00:03:57.360 | An interesting thing about your book is that actually the entire
00:04:03.120 | first part, not just the first chapter, but the entire first
00:04:05.800 | part isn't about your thing at all. It's about Yeah. It's about
00:04:10.520 | HTML and HTTP, I guess. So I wanted to start there because
00:04:14.920 | some of the like, so I've been coding for a while. And I hadn't
00:04:21.240 | quite noticed until recently that there's a whole generation
00:04:25.600 | of people who are competent full time coders that are not
00:04:33.240 | familiar with any of the basic concepts of the web because they
00:04:35.920 | program at a totally different level of abstraction, which is
00:04:38.320 | like, you know, React and JSX and all that. So I thought like
00:04:42.440 | it might be fun to go back to a an existing web 1.0 web page
00:04:48.920 | is Richard Storman's personal current website. Oh, yeah. Could
00:04:53.240 | you like just teach us a little bit about what's going on here?
00:04:56.200 | What are the underlying things? What's the buttons like? What
00:04:59.520 | are the what are the affordances provided by the web that
00:05:03.840 | Richard's using here?
00:05:05.400 | Yeah, yeah. So this is very much an old school, very, very old
00:05:09.480 | school web page, you know, and there's always been this tension
00:05:13.240 | on the web, like, is it a document? Is it? Is the web
00:05:16.640 | about documents? Or is it about something more than documents?
00:05:20.000 | And how and if so, how much more. And so here, you can see
00:05:24.960 | sort of a standard web 1.0 style web page with a bunch of links
00:05:29.400 | or anchor tags that link to various things and let you click
00:05:33.040 | on them. So I just click here. So inspect. So here is an anchor
00:05:40.320 | tag. So it's an anchor tag.
00:05:42.200 | Yeah. And so the important, the important thing here is the href
00:05:47.240 | attribute. So that href attribute, which specifies
00:05:51.640 | another URL, that when you click on the on the text that's
00:05:56.680 | included inside that tag, the browser, which is a hypermedia
00:06:00.800 | client is going to issue an HTTP GET. And it's going to take
00:06:07.800 | whatever the hypermedia response is to that and then load it into
00:06:11.520 | the browser. How it's loaded can be affected by a bunch of
00:06:15.640 | different things, affordances. So there could be a response
00:06:20.120 | header that tells it to do something specific, maybe do a
00:06:22.840 | redirect or something like that.
00:06:24.120 | Well, let's take a look because you know, we can something I
00:06:26.400 | definitely encourage people to do is to kind of watch their
00:06:30.040 | browser, doing that, which you can by popping up here. And if I
00:06:35.240 | refresh, we can see.
00:06:38.800 | Yeah, you go ahead and Yep, exactly. So you can see this is
00:06:44.360 | the response that came back from that GET request. And so you can
00:06:47.960 | see the request URL that was made to and just a bunch of
00:06:52.520 | these are these are headers, these are basically named value
00:06:54.960 | pairs. And there are some that are sent as part of the request.
00:06:57.920 | And then there are some that come back as part of the
00:06:59.720 | response as well. And that's, that's all tied up.
00:07:03.320 | And that's actually the body of the response. But I guess we
00:07:06.200 | should look at the response headers. Yep.
00:07:08.120 | Yeah, yeah, these are the response headers. So you know,
00:07:11.400 | there's an E tag in there. And that's what they actually all
00:07:13.800 | this. Yeah, that's what it looks like when it writes raw. Yeah.
00:07:17.680 | So HTTP. So the way you're looking at here is sort of a
00:07:20.600 | partial representation of HTTP, which is the underlying transfer
00:07:25.000 | protocol, the hypertext transfer protocol, it's what HTTP stands
00:07:28.360 | for. That's the that's the core network format for the web. And
00:07:34.280 | that's how web browsers in general make requests, even when
00:07:37.920 | basically, so I was just gonna say, so we basically have two
00:07:41.440 | affordances here, right? One affordance is like, underlined
00:07:45.280 | things I can click on just the links or anchors. And the other
00:07:49.480 | is a form I can fill out with a button. And one of the
00:07:52.480 | interesting things you point out in your book is, in terms of
00:07:56.320 | like, HTML itself, that's it, the entire set of affordances
00:08:02.160 | provided to interact with a web page. Are those two things?
00:08:06.040 | Yeah, yeah, affordance is a it's such a broad word that I think
00:08:10.200 | people could could argue about that. But those are the two
00:08:12.680 | primary interactive affordances. Or another term I would use for
00:08:17.520 | those is they're the two main hypermedia controls,
00:08:21.160 | interactive hypermedia controls in HTML. So, so taking a step
00:08:27.000 | back again, when you've got so how does the web work? Well,
00:08:30.440 | you've got documents, let's just start with documents. And this
00:08:33.880 | is a, this is an HTML document stored somewhere. And when that
00:08:38.440 | document comes down, embedded within the presentation
00:08:42.320 | information, are these interactive elements, the
00:08:46.200 | control elements is what Roy Fielding,
00:08:48.360 | the a tags and the form tags,
00:08:51.200 | a tag and a tags and forms. And you can also argue that like an
00:08:54.880 | image is a hypermedia control, because it's going to drive
00:08:59.320 | another request that downloads an image element that's then
00:09:02.520 | inserted. And so there's a you can get into the weeds and that
00:09:05.160 | kind of stuff. It's not
00:09:05.880 | interactive to use your terminology. Yeah, it's not it's
00:09:09.040 | not something that the user selects, you know, when Fielding
00:09:11.760 | talks about what makes the web special, he, he talks about
00:09:15.080 | users selecting actions based on
00:09:17.160 | Fielding. Sorry, Roy Fielding, Roy Fielding is the guy who
00:09:21.560 | wrote the famous or somewhat famous, it was much more famous,
00:09:26.000 | I guess, in the past, dissertation on the web
00:09:29.160 | architecture. And that's what gave us the term rest. Yep. So
00:09:33.320 | that dissertation, he and I'm going to be honest with you, the
00:09:36.960 | dissertation is a little hard to read. But, but one of these
00:09:41.560 | core ideas with the web has always been the embedding of
00:09:44.880 | interactive information directly in the document in the
00:09:49.000 | presentation information. And so you have this mixing of concerns
00:09:52.880 | between the presentation as well as the, the network stuff you
00:09:57.000 | can do with the presentation now in a document like, like
00:10:00.200 | fieldings, like, you know, it's hard for a lot of people. It's
00:10:04.120 | like, these are just links, they're just links to other
00:10:06.720 | documents. Yeah, that's true. But then that form starts to get
00:10:11.120 | at what really, you know, I think HTML two added forms, and
00:10:17.000 | when forms were added as a hypermedia control, that really
00:10:20.640 | is. Yeah. And so you can see there, it's action rather than
00:10:25.120 | href. I don't know if that's good or bad. There's a lot of
00:10:28.040 | inconsistencies in HTML. It's a very, it was grown very
00:10:31.160 | organically. And so as the text, but yeah. Yeah. And so forms are
00:10:37.160 | much more complicated, because they, you know, the the form of
00:10:41.560 | the request that's made depends on the state of the inputs
00:10:44.040 | inside the form and all this other stuff. You can also issue
00:10:48.000 | posts. So you see there, it says method equals post. So it's
00:10:51.600 | going to make a, it's going to make an HTTP POST request rather
00:10:54.880 | than a GET request, which is what we saw for the links. And
00:10:58.760 | so the forms when forms were added in HTML two, I think
00:11:02.960 | that's when the web went from really sort of a traditional
00:11:07.680 | hypermedia system, like the old school documents, like the way
00:11:12.600 | the web kind of grew up was it was, it was more of a document
00:11:17.080 | oriented system. And when this form came along, it was sort of
00:11:21.240 | like a spark that made it possible now to build app web,
00:11:25.080 | what we today call web applications. And I don't know
00:11:29.360 | how much thought went into that, like how revolutionary that
00:11:33.200 | I mean, I remember at the time it happened, it was, it was
00:11:37.760 | exciting, because like, going behind the scenes as to what
00:11:41.160 | happens, like when a POST request happens is the contents
00:11:44.920 | of that form gets sent to your server. And then at that point,
00:11:50.360 | you can run any program you like, do anything you like, and
00:11:54.560 | send back a response. And so I remember it was like an exciting
00:11:58.040 | time for the internet, because suddenly, you could compute on
00:12:04.160 | these things.
00:12:05.440 | Yeah, they really converted the web from a document, you know, a
00:12:09.960 | document based, like kind of like gopher, and I go and go for
00:12:12.960 | wasn't a great example. But there were a bunch of these sort
00:12:15.920 | of document oriented hypermedia systems that were around even,
00:12:20.440 | you know, low, just purely local ones. But when once you got
00:12:24.960 | forms that now you have a distributed application
00:12:27.600 | architecture, and now and not necessarily a good one in many
00:12:31.480 | ways, but but had some real big advantages to it. The primary
00:12:36.240 | one being that there was this sort of universal client, the
00:12:39.360 | browser that was available everywhere. And so to give your
00:12:43.320 | application to people, you just had to give them a URL. And that
00:12:46.600 | was it. And that's, you know, that's one of the that's one of
00:12:49.120 | the reasons why the web, despite all the problems with it, has
00:12:52.840 | has done so well.
00:12:54.080 | Yeah, well, let's talk about those, like, limits or
00:12:57.520 | constraints or whatever. So I will, you identified them, and
00:13:03.760 | you list them in the book very eloquently. So I'm just going to
00:13:08.200 | go ahead and tell you what you told me. So, so some key
00:13:12.320 | limitations here of these interactive affordances. Okay,
00:13:16.960 | number one, there are only two types of things that can
00:13:21.960 | interactively generate a request. One is the anchor tag.
00:13:24.880 | The second is the form. Number two, anchor tags can only call
00:13:31.520 | get request. Forms can only call a get or a post request. So
00:13:39.120 | they're pretty limited in what they can do. So they're limited
00:13:42.880 | in terms of the elements, then they're limited in terms of like
00:13:45.160 | what, what interaction can cause a request. And so, in this case,
00:13:51.160 | only clicking a link or clicking a button can cause a request. So
00:13:55.200 | things like scrolling, you know, moving a slider, scrolling
00:13:58.360 | something into view, typing on the keyboard. And then I think
00:14:03.400 | perhaps the one I found most interesting, because it just
00:14:06.840 | seemed such a such an obvious implicit thing to me, I'd never
00:14:11.840 | realized it was a constraint, is that when you click on a button,
00:14:15.520 | you know, yeah, or, or a link, the information that comes back
00:14:22.360 | from the server, there's only one thing that the browser can
00:14:24.560 | do with it, which is to replace the entire web page. Although in
00:14:31.000 | this case, it looks like maybe Richard Stallman's site search
00:14:35.720 | button actually doesn't work. But oh, yeah, here it comes
00:14:38.560 | eventually.
00:14:39.200 | So what you what you just saw there is one of the problems
00:14:42.600 | with the web, right? There was no visual before, like the
00:14:45.760 | browsers have actually gotten much worse at this, telling you
00:14:48.720 | hey, something's going on, like, wait.
00:14:51.040 | Yeah, so the result came back from the browser. And the result
00:14:56.560 | of that, in fact, I guess we could do the same thing we did
00:14:59.240 | before, right, which is we can go into our network tab. And if
00:15:04.880 | I refresh this, it should be an option to refresh the post
00:15:07.760 | request. And we should be able to see it here it is. So there's
00:15:15.720 | the post request. And the request headers include, you
00:15:23.720 | know, various things. But I guess the interesting one is the
00:15:26.240 | payload, which is the form data. The response thing comes back,
00:15:30.760 | which is HTML. That's the body of the response. And so the
00:15:35.520 | server, yeah, tell us about what happened then really on the
00:15:38.520 | server when it received this HTTP.
00:15:42.000 | Yeah. So the server received that post request HTTP is a very
00:15:47.440 | simple network format. If you've done if you've ever studied any
00:15:51.360 | sort of networking at all. It's very simple. And so the those
00:15:56.200 | name value pairs were encoded in the body that was sent up. And
00:16:00.240 | so one of the one of those values was the search term. And
00:16:03.040 | then on the back end, there's some program that executes and
00:16:06.680 | figures out which pages have that term that you've passed up
00:16:10.360 | on it, and then constructs URLs to link to them and then
00:16:13.440 | presents that beautiful search result that we saw in the in the
00:16:18.200 | screen. And it's sort of a full page thing. And there. I noticed
00:16:23.320 | that they did not use the very common, first of all, they used
00:16:27.920 | a post rather than a get. And arguably, that's not correct.
00:16:31.640 | Because for a search, you're not you're not asking it to mutate
00:16:37.000 | anything. And so you probably would using a get would actually
00:16:42.960 | make like the input values would end up in the URL, and then you
00:16:48.520 | would have a copy and pastable search, URL and so forth. And so
00:16:53.080 | I noticed that they also didn't do a redirect. So when you hit
00:16:56.840 | refresh, you saw another post. Yeah. And depending on exactly
00:17:00.600 | what the post does, that can be a bad thing, right? Like it buys
00:17:03.800 | a ticket, you know, it could buy another ticket. So it's, you
00:17:06.960 | know, just this is sort of like the old school grunky web that
00:17:09.800 | we're looking at.
00:17:10.280 | Okay, so yeah, so this is the thing that blew my mind, Carson
00:17:14.320 | is that you identified these four specific constraints of
00:17:19.040 | what a web browser can do. And those constraints are determined
00:17:24.440 | by the specs themselves, right? And somehow, and we'll come back
00:17:29.880 | to how later, I don't know how, but somehow, you realized, or
00:17:34.520 | asked the question, what happens if we remove these four
00:17:37.000 | constraints? You realize that we can using JavaScript, and then
00:17:43.680 | with the right script, it's almost like a polyfill for the
00:17:46.640 | browser. It's almost like saying, let's pretend the
00:17:49.600 | browser didn't have those constraints. And like, so just
00:17:52.320 | adding a single script tag, it's like, okay, now the browser
00:17:54.680 | doesn't have those constraints. And so that is HTMX, right?
00:18:00.080 | HTMX is like the polyfill, where we say, let's pretend the
00:18:05.040 | browser doesn't have those constraints. And so you have
00:18:09.400 | then a bunch of examples here, right, such as click to load.
00:18:16.880 | And it is still, let's find it here. Okay, so you've got a
00:18:25.280 | table, right? And in this table, when I load more agents, it
00:18:33.000 | loads more agents that it did not refresh the screen. And, you
00:18:39.520 | know, the actual button here, which is in the last row of the
00:18:43.440 | table, we've got a new one now, but here we are in the last row
00:18:47.320 | of the table.
00:18:47.960 | Yeah, it'll call span, good old center tag and call span three.
00:18:53.320 | Here it is. Now you're not, you know, this button, it's, you
00:18:59.440 | know, it's not in a form. It doesn't do a submit. It's like,
00:19:05.400 | but it's all still just HTML. And on these examples, I love
00:19:10.520 | that I can actually click show. And it actually shows me the
00:19:17.440 | HTTP request that happened, right? The HTTP response that
00:19:23.000 | happened. And so we've got something that looks, in a lot
00:19:28.680 | of ways, a lot like Richard Stallman's website. But it
00:19:34.000 | behaves like a modern, you know, SPA style app. So I guess like,
00:19:42.360 | I was thinking like, well, maybe we should, like, how do you
00:19:46.040 | think this is best to explain? But like, how is it like, what
00:19:49.560 | are the constraints that we've kind of removed here? And how
00:19:52.560 | is removing those constraints, in this case, allowing this
00:19:56.280 | button to do this thing? Because...
00:19:58.320 | To do some magic.
00:20:00.280 | Yeah. And actually, maybe before we do, I'm going to switch over
00:20:03.680 | to a version where we get to see the server. And of course, I
00:20:07.440 | then get to show off FastHTML, which is like an extremely
00:20:11.600 | simple wrapper, largely around the genius of Carson's work, and
00:20:15.520 | also the genius of something called ASGI. And the details
00:20:21.240 | don't matter. But here, this is basically says, this is a route.
00:20:24.200 | So when you go to slash, call get, it's going to return a
00:20:28.920 | table with a table header with name, email, and ID, a table
00:20:34.280 | body with five copies of making a row, which has an agent and a
00:20:39.720 | null.org and an ID. And at the bottom, it's going to have that
00:20:45.160 | button that we saw. And so if we run this, I think it's kind of
00:20:52.800 | fun looking at it on the server, because we can now see the
00:20:54.960 | server running. So if I go there, you can see something
00:20:59.400 | looking pretty similar, and I just do one at a time, load
00:21:01.280 | another agent, click. Sure. Click. Yep. And yeah, it's
00:21:07.080 | it's actually calling when I click this button. It's actually
00:21:14.920 | calling more. And more is just returning, you know, another row
00:21:24.760 | plus, yeah, add row. And if we look at the network tab, when we
00:21:29.360 | click load another agent, we can see more. And it looks very
00:21:36.360 | similar. It's a get request, it's to a URL, it's got
00:21:39.200 | headers. But the response is pretty weird looking. So yeah,
00:21:47.680 | where do you want to start? How do we how do we learn about how
00:21:50.200 | these?
00:21:50.560 | Well, let's go look at the let's go look at the button. Look
00:21:54.720 | at it. I think you just inspect it. And we can go through each
00:21:57.640 | of the attributes on it. So basically, HTML consists of
00:22:01.320 | attributes, they put in your HTML, because that's how HTML
00:22:04.800 | has worked, you know, you use attributes to specify network
00:22:08.880 | interaction behavior. And here, there's three attributes. So
00:22:12.800 | HX get HX target and HX swap.
00:22:15.400 | So they've all got an HX dash on the front. So does that mean
00:22:19.120 | Yeah, all of the stuff you're adding is always going to be
00:22:21.840 | have this pretty Yeah, yeah, we use the HX prefix to namespace
00:22:26.760 | it effectively. You can also some people prefer using data
00:22:30.320 | dash HX because that's more that's in spec. But I've been
00:22:34.360 | told by the browser people that this will never break a browser.
00:22:37.560 | So so I like the shorter version of it. But what HX HX get says
00:22:43.240 | it's effectively the same as a trough. It's saying, here's a
00:22:50.200 | URL that I want you to interact with, like, here's a here's a
00:22:53.120 | hypermedia endpoint that I want you to interact with. And that
00:22:56.040 | endpoint is then specified as slash more, which you've set up
00:22:59.560 | a handler for.
00:23:00.400 | In fact, let's just take a look at that. So here's my more. So
00:23:04.720 | when Yeah, so when somebody clicks this button, it's going
00:23:08.440 | to send a request to and a get request. And now I get and this
00:23:15.640 | is the thing that I find a lot of people don't understand
00:23:17.720 | people like are you using PyScript or wasm? Or like, how
00:23:21.080 | are you getting Python in the browser? And it's like, we're
00:23:25.080 | not this is running on the server.
00:23:27.360 | Yep, yep. Yeah, everything's it's it's much it's much more
00:23:31.880 | like the traditional web application where your HTML I
00:23:35.200 | don't want to say it's dumb, necessarily. But it's it's just
00:23:38.040 | everything specified in terms of what I would call hypermedia
00:23:41.640 | interactions, rather than in terms of, you know, sort of
00:23:45.080 | programmatic interactions, where you're consuming an API and
00:23:48.200 | building stuff sort of locally in the browser. So that first
00:23:52.240 | attribute hx get is specifying sort of where to send the
00:23:54.960 | request to and how to send it. So you can do hx post if you
00:23:57.840 | wanted it to be a post for some reason, or whatever. But hx get
00:24:01.280 | makes sense here. And then the next attribute is hx target. And
00:24:05.760 | this is really I think, this gets at that last element of
00:24:10.400 | I think, yeah, probably. Yeah, I agree. I think it's the most
00:24:14.320 | important one. What this lets you do is say, okay, you're
00:24:18.040 | going to get back some HTML from this slash more URL from this
00:24:22.040 | request, this get request you make to that URL, where do you
00:24:24.960 | want me to put it?
00:24:25.680 | So normally, it would just be like, just replace the whole
00:24:30.000 | page. And I call that a full the full page refresh. That's the
00:24:33.560 | normal. Exactly. So that and that's what links and forms do
00:24:36.840 | by default in HTML by default. And so this allows you to say,
00:24:41.280 | okay, when that HTML comes back, I want you to put it here. I
00:24:44.640 | want to put it here it is here is hash replace me. So you're
00:24:47.800 | using CSS, select a syntax there. Yeah, exactly. So we
00:24:51.440 | decided to reuse the CSS, like just it's universal people
00:24:54.400 | understand it. Yeah, we do. And so that tells that tells htmx
00:24:59.640 | where to put the content that comes back from the server. And
00:25:02.840 | then the the next attribute, which is hx swap, tells htmx
00:25:07.880 | how to place it. So in this case, we want to replace the
00:25:12.600 | entire table row with two new table rows. Right. And so that
00:25:16.680 | that so there were two new table, actually, maybe we should
00:25:19.280 | just look at that network tab again to see the two table
00:25:22.600 | rows. Yep. Okay, so here's the response we get back, there's
00:25:28.080 | the table row for the new agent. And there's just a copy of
00:25:31.880 | right, basically the one we just saw. Yeah, same button, right.
00:25:35.200 | And it's gonna replace my name, same element, and so forth.
00:25:38.880 | Yep. And so, you know what, with this, this new HTML is now
00:25:44.760 | going to replace the entire existing table row. And so
00:25:49.000 | that's what because of that, and that's going to replace the
00:25:53.560 | entire thing. Now, there's there are other options. So for
00:25:56.120 | example, you could say, let's use one, let's use one now,
00:25:58.720 | because actually, I think we could like, simplify this a
00:26:01.760 | little, right? If we took the table, and if we gave the table
00:26:06.480 | an ID, okay, so we give that there. And then like, we could
00:26:11.480 | just like, say, Alright, let's like, can we kind of like do
00:26:16.280 | something like this, where we just return one row, maybe like
00:26:21.280 | return it just before the,
00:26:24.240 | I would change that to a, I would change. Let's see, how
00:26:28.840 | would I do this, I would, I would make add row no longer in
00:26:33.280 | the table, I would put it after the table.
00:26:35.440 | Yeah, exactly. So let's just grab the button.
00:26:39.200 | Grab that button and move it out of the table.
00:26:42.720 | And let's just do exactly. Okay, and so we don't need add row
00:26:48.080 | anymore. And we can take the ID off of it. Okay, that makes
00:26:54.200 | sense. Body, I kind of like these little lines that VS code
00:27:00.640 | can add. So you can kind of see this is where the T body is.
00:27:03.760 | Okay, I would put it on the T body.
00:27:07.040 | T body. Okay, well, in that case, I'll do that, too.
00:27:09.200 | Because that's where that's where we're gonna, that's where
00:27:11.880 | we're gonna append the thing, right?
00:27:13.400 | Ah, okay. All right, we can do that for sure. So okay. We've
00:27:22.400 | now got T body, we've got these rows, add row, ID equals agents.
00:27:29.920 | Okay, that looks pretty good to me. Okay, so now we don't have
00:27:34.680 | an add row anymore. That's easy.
00:27:36.880 | Sorry, I'm learning fast HTML as we go.
00:27:40.880 | Please, absolutely. Yeah. The interesting thing about fast
00:27:46.800 | HTML is because it's a direct mapping, like one to one
00:27:49.440 | mapping. So in fast HTML, the it kind of there's a almost unique
00:27:56.040 | thing about Python, which is in Python, you can have positional
00:27:59.320 | and named parameters. And here you can see this doesn't have a
00:28:02.680 | name. And so you can have as many of these as you like, and
00:28:05.480 | they become positional parameters. So they're children.
00:28:07.640 | And then you can have as many of these as you like. And as you
00:28:10.560 | can see, these are named keyword arguments, and they become
00:28:14.480 | attributes. So it's kind of like the mapping between HTML and
00:28:18.760 | Python function syntax is almost uniquely perfect.
00:28:23.080 | Yeah, yeah, yeah.
00:28:25.720 | Okay, so now what we want to do is we want to change HX target
00:28:29.800 | to be agents, because we're going to target that T body with
00:28:33.600 | the response. And then, rather than outer HTML, we're going to
00:28:38.920 | I'm gonna have to go look this up. HX.
00:28:41.480 | I gotta say the reference for HTMX is great. I just type
00:28:45.480 | HTMX reference. And it's really nice. And here they all are core
00:28:51.160 | attributes.
00:28:52.000 | Yeah. So we want to we want to for if you look at HX swap, we
00:28:56.080 | want before and that's the terminology that the DOM API
00:29:01.320 | uses to insert something before it because we want to insert
00:29:04.440 | this new row before the end of the T body, not after the T body
00:29:08.880 | but like, as its last child effectively. So before and as
00:29:12.520 | the right HX swap for that, I think.
00:29:14.560 | Nice.
00:29:15.120 | So I think that should work. And now what's going to happen is
00:29:19.760 | there it is. Yeah. And if we
00:29:23.160 | Amazing.
00:29:23.720 | inspect, not at all. Then we should see
00:29:29.200 | I'm always a little shocked when my stuff works.
00:29:31.200 | So now we've just got one thing coming back. So I think this is
00:29:34.880 | a great example of like, what happened here. So maybe just
00:29:38.440 | talk us through this revised button here.
00:29:46.200 | Well, so we moved it, we moved the button out of what we were
00:29:50.000 | replacing, like previously, we were replacing the button with a
00:29:54.440 | new version of itself. And that makes sense when you're doing
00:29:56.880 | things like for example, loading another page, because you want
00:29:59.800 | to update the you want to update the URL with like the next page.
00:30:04.400 | So when you load the second page, you want the button to
00:30:06.760 | then load the third page. And so you want to have a chance to
00:30:09.480 | update the URL. So it makes a lot of sense in sort of a click
00:30:13.080 | to load more scenario. But here, when we're just like adding new
00:30:16.680 | rows to to a data structure, it doesn't make as much sense, you
00:30:21.480 | kind of want it, you're hitting the same URL over and over
00:30:24.120 | again. So in that case, why not move the button outside of the
00:30:27.920 | target area. And this is the same, you're just going to
00:30:31.080 | HX get is the same. The target is a little different. We target
00:30:36.680 | the T body because that's where we want to put the new content.
00:30:39.360 | It's not we're not replacing a parent. Yeah. And and then that
00:30:43.840 | beforehand says, okay, when you get a response, I want you to
00:30:46.920 | stick it before the end of that T body. So that's the that's the
00:30:50.560 | DOM way of saying like at the end of the children.
00:30:53.080 | So I think something that I didn't understand at first is
00:31:01.280 | how extremely small the surface area of what HTMX touches is,
00:31:06.680 | you know, and it's basically the core attributes. And there's
00:31:09.320 | also, I just having a look. Yeah, there's a few more here.
00:31:14.560 | Well, some of them are really obvious, like, oh, this is just
00:31:17.040 | the same thing, but a different verb. Yeah. Almost none of those
00:31:20.360 | I've used. So I can say confidently, this is basically
00:31:23.080 | the surface area that normal people like me need. Yeah. And
00:31:27.600 | then like you kind of said, the, even the contents of them are
00:31:33.120 | like, copied and pasted, like to the name, the semantics,
00:31:38.240 | everything to like how the DOM works. So it's like, right, kind
00:31:41.840 | of like very direct mapping. And even then you've also like got
00:31:45.120 | two versions of swap or B or not two versions of select or B or
00:31:48.760 | not. So there's like, it's a very small little set of stuff
00:31:54.160 | to know. And when you know the basics of how the browser and
00:32:00.080 | the web works, it's super natural. That's my experience
00:32:04.920 | with it.
00:32:05.200 | It well, I think it rhymes really well with the web, like
00:32:10.080 | it goes with the grain of the hypermedia infrastructure. And
00:32:13.320 | so if you're familiar with and comfortable with that, which as
00:32:15.960 | you pointed out, a lot of younger people aren't a lot of
00:32:18.680 | younger web developers, I should say, aren't, then I think you
00:32:22.760 | come across as being very foreign, you know, so I think
00:32:26.040 | that's why you see some of the misunderstandings around HTMX,
00:32:29.480 | just like, Oh, this is terrible. Like, why would you do this?
00:32:32.200 | Everything has to be a network request. Well, not everything.
00:32:34.720 | Yeah. So I think it's not, it's also like, surprisingly fast,
00:32:42.240 | because the kind of full page refresh, I think, often it feels
00:32:47.160 | slow, and it is slow, it feels slow, because you see the whole
00:32:50.800 | thing flashing and changing. It is slow, because it requires
00:32:53.880 | like the browser reparsing the CSS and rehandling any
00:32:57.000 | JavaScript and relaying everything out. But when you
00:33:00.800 | just insert, so this is what I noticed, you know, when I was
00:33:05.480 | showing the CEO of Vercel this, you know, and he was trying it
00:33:10.240 | out. And particularly because like, Vercel has this kind of
00:33:13.320 | edge caching thing working. And he was just like typing and hit
00:33:16.840 | enter. It's like, boom, boom, boom. He's like, his mind was
00:33:19.680 | blown. He didn't, you know, he was like, I didn't know this is
00:33:22.160 | what the hypermedia application can feel like.
00:33:25.680 | Yeah, it can feel really good. And the browsers are very good
00:33:29.600 | at displaying hypermedia. Some would argue that's what they're
00:33:32.520 | designed to do. And so, you know, I think, yeah, the, you
00:33:38.120 | know, obviously parsing, like little bits of HTML, that's
00:33:41.760 | something that browsers incredibly fast at and inserting
00:33:44.280 | it into the DOM is also very fast. Yeah. And so if you're not
00:33:47.800 | trying to do a bunch of like reconciliation logic, like a lot
00:33:51.200 | of SPA libraries do, you can be very fast, you don't, you are,
00:33:55.440 | you know, to an extent, you're more dependent on network, like
00:33:58.280 | network latency.
00:33:59.400 | I guess you're in Australia. So I have the worst, because I'm
00:34:02.640 | using American servers, and I'm in Australia. And so the speed
00:34:07.080 | of light basically means our ping is 70 milliseconds plus.
00:34:10.960 | Right? I gotta say, it's not bothering me. Can we can we pick
00:34:16.080 | another one maybe? So we've looked at like, okay, the what's
00:34:18.600 | maybe the most important, which is, you can arbitrarily update
00:34:24.320 | the DOM of the existing page just by passing back an HTTP
00:34:28.720 | response. Maybe another one to talk about then would be like we
00:34:31.880 | can respond to events other than clicking something. Is there a
00:34:36.520 | good sample here for?
00:34:38.280 | I'm gonna always point at active search as being well, we could
00:34:42.360 | do lazy loading, or do active search, which one?
00:34:45.000 | Okay, so here's active search.
00:34:47.720 | And this is I have to say this. Yeah. So like AES is what I
00:34:55.440 | always do.
00:34:56.000 | Yes. Okay. And I didn't hit enter. So I'm just typing
00:35:00.400 | backspace, backspace. Hey, yeah. And let's have a look. We've got
00:35:05.040 | so I've typed five things that resulted in five requests. And
00:35:10.560 | so now interestingly, it's obviously done some debouncing
00:35:14.160 | because I typed AES fast enough, it just sent one request. And
00:35:17.200 | then I started typing backspace, wait, backspace, wait. This time
00:35:22.720 | I typed it slower. And so I can see it's basically it looks very
00:35:28.120 | normal from what you've described. So far, we've got a
00:35:30.840 | post, it's got some data. Yeah, this response. So should I look
00:35:36.720 | at this element to see how I would I would go up and we can
00:35:41.120 | look at the highlighted code. It's a little easier to explain
00:35:43.280 | if you go to the top there. Okay. Let's zoom in a bit. So
00:35:47.120 | this is that's a obviously a pattern people are familiar with
00:35:50.160 | from like Google and like a lot of more advanced web apps. And I
00:35:54.600 | called it active search. I think I forget what Google calls it.
00:35:58.160 | But and this is achieved with four htmx attributes, really
00:36:02.760 | three plus one, we'll talk about at the end. But we once again
00:36:06.680 | have an HX post here we have HX post instead of HX get because
00:36:10.360 | we're issuing a post I in an ideal world, this should be a
00:36:13.640 | gap, but I won't go into the reasons why we don't need to see
00:36:16.520 | the the server side code for this. But like it's pretty
00:36:19.600 | obvious what it would do or take the right data, it would do the
00:36:23.040 | search and it would return the HTML that we just saw. Yeah,
00:36:27.480 | exactly. And really the big the big difference here, the thing
00:36:30.440 | that's new here for for people who are watching this and have
00:36:34.120 | never done any I've never seen htmx before, is this HX trigger
00:36:38.400 | attribute. And what that HX trigger attribute specifies is
00:36:42.560 | the event that's going to trigger a request. And so it's
00:36:47.160 | the event that we use as input. And then there's a couple of
00:36:51.240 | modifiers on input. The first one is changed. Let's just go
00:36:54.480 | back. So tell me what is the event input? Is that a normal
00:36:59.200 | grammar knows? Yeah, exactly. Input is a is a standard DOM
00:37:03.640 | event that you can look up like on Mozilla on MDN. And it
00:37:09.000 | basically corresponds to a key up. But when it's it's when when
00:37:13.200 | the input changes in an in an input of some sort. So it's
00:37:17.520 | going to be triggered by checkboxes like when you check
00:37:20.120 | them and uncheck them. With text boxes, it's triggered whenever
00:37:23.880 | the text changes. And this is something I really like about
00:37:28.160 | htmx is when I want to know how to do something, you know, and
00:37:34.200 | it's nearly always like, Oh, well, this is just doing this
00:37:36.800 | DOM thing, then the doc, then the document I search is like,
00:37:40.760 | you know, Mozilla web docs. Yeah. It's not like, oh, here's
00:37:48.600 | the special dashboard abstraction that Carson wrote,
00:37:53.160 | or whatever. It's just like, no, it's just the web, man.
00:37:56.240 | Yeah, yeah, I tried very much to lean on existing ideas. So you
00:38:00.520 | know, again, as you pointed out, the HX swap attribute uses the
00:38:04.000 | standard DOM name, like they're not the names I would pick, but
00:38:07.800 | I just figured, you know, we might as well stick with as much
00:38:10.680 | as possible with what the standards are. Yeah. And so we
00:38:13.920 | tried to do the same thing with fast HTML, you know, like I say,
00:38:17.080 | like, you know, there's a lot of people who have tried 1000
00:38:19.600 | different functional HTML builders. And I thought like,
00:38:24.600 | well, you know, HTML is kind of XML, their tags, they have a
00:38:30.920 | name, they have positional parameters, they're called
00:38:34.680 | children, they have keyword arguments, they're called
00:38:37.160 | attributes. Python has those things. So it's just those
00:38:40.880 | things, you know, it's kind of like, I think this thing of
00:38:42.880 | like, embrace the technology you're working with is a theme
00:38:48.600 | that I think we're both going for here.
00:38:50.680 | Yeah, like, I like the term rhyming, you know, make it rhyme.
00:38:55.000 | Yeah. And so I don't know, but that just appeals to me. So in
00:38:59.480 | any event, yeah, input is a, it's a standard event. And it
00:39:02.520 | could be any event, you know, you could even use and people do
00:39:05.200 | do this, you can use custom events to trigger requests, if
00:39:08.360 | you have done that was very helpful.
00:39:09.920 | And you could delete all this. This is like a bit of extra.
00:39:13.560 | Yeah, extra coolness. But all you actually need to make this
00:39:16.960 | work is just this one word.
00:39:18.680 | Correct? Yeah. And so the next two things are modifiers for
00:39:22.320 | that event. And so there's the change modifier, and then the
00:39:25.520 | modifier. And the change modifier tells HTMX only issue
00:39:31.840 | a request if the value of this input has changed. So you don't
00:39:36.120 | want to like if someone hits an arrow key, for example, that's
00:39:38.720 | not a reason to issue a new request. And then the delay, you
00:39:43.040 | notice that there was some sort of D bouncing going on. And
00:39:45.720 | that's what that delay colon 500 milliseconds is doing. Yeah,
00:39:49.120 | that's saying basically, when an input occurs, wait 500
00:39:52.720 | milliseconds. And if another input hasn't occurred, issue the
00:39:56.120 | request. Otherwise, just reset the timer.
00:39:59.440 | So Carson speaking as like a user, something that I like a
00:40:04.000 | lot about this, but at first made me nervous is a lot of the
00:40:08.240 | code I saw, including on your website, had like, a lot of
00:40:13.640 | unfamiliar words in unfamiliar syntax. And I thought, I'm not
00:40:17.640 | clever enough to understand this. But then I quite quickly
00:40:20.680 | realized, like, you can delete most of them. And it still
00:40:25.560 | works. The bits I recognized, which is like respond to this
00:40:29.440 | event, like a fine. And so I actually found it suited me
00:40:33.400 | quite well to gradually learn these extra bits. And your book
00:40:39.960 | is great at this. So the entire first section is about web 1.0,
00:40:47.360 | you have an application branch. All of section two is about
00:40:53.280 | HTMX. And you introduce it like, super gently, you know, right.
00:41:00.360 | And just one little bit at a time. So you know, I would
00:41:05.000 | encourage people to just go through this book. And then the
00:41:11.840 | other thing to say is the mapping between just like the
00:41:15.200 | mapping between HTML and fast HTML functions is a simple
00:41:20.000 | one-to-one mapping. The mapping between HTMX attributes and
00:41:26.760 | fast HTML attributes is also a one-to-one mapping. You just
00:41:31.240 | literally replace the hyphen with an underscore. Yeah. So
00:41:36.280 | like, you know, folks could go through, I think folks should go
00:41:40.000 | through this book and build applications. And if you're a
00:41:44.320 | Python programmer, you don't have to learn any JavaScript.
00:41:48.400 | But in the process, you'll be learning a little bit about,
00:41:50.840 | you know, JavaScript things and HTML things like HTML. But you
00:41:55.320 | know, this book is a really great way to gradually build up
00:42:00.080 | to understanding these like optional extras, in my opinion.
00:42:03.360 | Right. Yeah, no, it's always tough to balance like, you know,
00:42:07.720 | you want to you want to be useful for the advanced users,
00:42:10.920 | but not too hard on the new users and so forth. So it's, it
00:42:15.160 | is tough. I do think the book is pretty good at making it a
00:42:19.480 | general introduction. I appreciate you saying that. So
00:42:23.400 | and then there's a comma in there. And then there's so the
00:42:27.600 | events are comma separated. So there's also a search event.
00:42:30.560 | Okay, so this is event number one, which is an input event,
00:42:35.400 | but only if it changed. And only if there hasn't been one within
00:42:38.680 | 500 milliseconds. And this is like or, yeah, or this is a
00:42:43.800 | search event. What they search event, search event is triggered.
00:42:48.080 | For example, scroll down to the UI. So what browser are you
00:42:55.280 | using? You're using Chrome? Okay, so that little x on the
00:42:57.520 | side there. Yeah. When you click that, a search event occurs. I
00:43:04.360 | don't know an input may also occur there. I need to actually
00:43:07.800 | because it was Yeah.
00:43:08.600 | And that's because like, there's a lot of stuff in HTML nowadays,
00:43:12.240 | including this type equals search.
00:43:14.360 | Yeah, exactly. And so so that search and there's I think there
00:43:19.240 | are other like keyboard shortcuts. I don't know the
00:43:21.120 | details of it. But we felt like, okay, we're gonna, we're gonna
00:43:24.480 | issue a request on the search event as well.
00:43:26.480 | And like I just showed example here. So we use this thing by
00:43:31.800 | default, you can use whatever styling we like, but by default,
00:43:35.960 | we use this thing called Pico, which I'm sure you're familiar
00:43:38.560 | with. And one of the things I like about Pico is it really
00:43:44.000 | leans in also to the idea of like, just embrace, you know,
00:43:48.080 | the web. And so here's a rather nice, reasonably, you know,
00:43:53.800 | reasonably nice looking search box. Right. And as you can see,
00:43:58.360 | it's an input with type equals search. Yep. And a button, you
00:44:04.040 | know, and in fact, the source code for this is literally form
00:44:10.960 | of equal search. So yeah, I think by like embracing the
00:44:14.680 | stuff that's available in HTML, and then joining it together
00:44:18.400 | with things, other things that embrace that like Pico and like
00:44:20.960 | HTMX, you can have very kind of, I don't know, it feels like the
00:44:26.520 | stuff you learn as you put this together, all joins up together.
00:44:31.160 | It's very different to learning like, this dashboarding system,
00:44:35.680 | and you want to use a different dashboarding system, throw away
00:44:39.360 | everything and start again, you know?
00:44:41.120 | Yeah, no, I agree. I think that's a good thing about
00:44:44.480 | HTMX. And Pico CSS is a great library as well. And that it's
00:44:49.520 | just it, it, it does, you know, again, rhyme with like, and
00:44:54.160 | tries to reuse the existing concepts of the web or other
00:44:57.440 | than imposing a bunch of new sort of mental categories on top
00:45:01.960 | of it. So
00:45:02.600 | yeah, okay, so that Okay, so either search or input. All
00:45:07.920 | right. And then target we've seen so the search results and
00:45:11.080 | this is a kind of a common pattern that I guess we see with
00:45:15.240 | HTMX is you kind of start off generally, let's just like
00:45:19.560 | close, let's just refresh this, you kind of start off with
00:45:24.560 | so you've got a table, if you open that table up, there's a
00:45:32.920 | table body in there that's got nothing in it, but it has that
00:45:35.640 | ID on it. Yeah. And so we're targeting that that that T body,
00:45:39.920 | and the default swap is going to be inner HTML. So what HTMX is
00:45:44.760 | going to do is take the response that comes back and then put it
00:45:47.640 | inside of that element. And so that works for this. So yeah,
00:45:55.080 | that's the that's the idea there. And then there's a last
00:45:58.720 | attribute, which is kind of a new one, the AJAX indicator, I
00:46:01.800 | haven't used this yet, but people rave about, okay. Yeah,
00:46:05.000 | you use that it takes a CSS selector, and that you can point
00:46:09.360 | it at an element, and it'll basically show that element
00:46:13.200 | while the request is in flight. And that addresses that issue
00:46:16.320 | you saw on Richard Stallman's web page, where you click the
00:46:19.040 | button, and it seemed like nothing happened for a second,
00:46:21.760 | because it was Oh, I see that searching thing popped up. Yeah.
00:46:24.680 | And so I see it. But yeah, yeah. I was so sometimes I make this
00:46:29.920 | slower. So that like, yeah, I can see the indicator. Yeah. And
00:46:33.800 | then people complain that HTMX is slow. And then I speed it up.
00:46:38.320 | And then they don't see the indicators. Okay, great. Yeah.
00:46:42.640 | Let's that's what that's there for.
00:46:44.320 | Do you have a hard stop at some time? I just want to think how
00:46:47.560 | much time to spend on different things.
00:46:49.440 | I don't I can talk.
00:46:51.200 | So let's look at the lazy loading one, then. That's okay.
00:46:55.960 | So here's that demo.
00:46:58.200 | Tokyo. So here, refresh, refresh. Okay, refresh. And
00:47:03.280 | you'll see like, this is a big indicator. And then I see. So if
00:47:07.000 | I scroll with let me just I think I understand. So if I make
00:47:10.040 | this smaller, yeah. And then I do that. And then I scroll to
00:47:15.200 | it. I see it's kind of happening in the background. And yeah,
00:47:18.480 | okay, cool. So the reason for that is, if I wanted to, like,
00:47:21.560 | have something I could start reading, or else something else
00:47:24.160 | was busy calculating underneath. Is that what's happening?
00:47:26.720 | Yeah, this is a this is a good pattern for when you have some
00:47:30.960 | some information that is maybe even even if it's important,
00:47:35.280 | it's something that you don't want to block the rendering of
00:47:38.200 | the first render of the page, you don't want it to block that
00:47:40.760 | first load of the page, because it's going to take a while. So
00:47:43.560 | this is just I mean, it's just a dumb image, like, but it's a
00:47:46.400 | stand in for Okay, here's some complicated stuff that we did to
00:47:50.080 | compute, you know, Tokyo's climate or whatever. Yeah. And
00:47:53.960 | so the important thing here is that the rest of the page
00:47:58.000 | renders very quickly. And then, and then we can issue this
00:48:02.760 | request, sort of when the page loads to sort of have a second
00:48:08.160 | error request, it's going to bring in the expect the expense
00:48:10.600 | of computation. So looking at this div, we want to once again,
00:48:15.160 | have an HX get where we're going to issue a request to URL that's
00:48:18.680 | going to make presumably take a while because it's expensive.
00:48:21.360 | And now this presumably would be basically returning an image
00:48:24.920 | tag or like a div with an image tag, an image tag or whatever.
00:48:28.520 | Yeah, whatever. And then that'll get loaded into wherever the
00:48:30.880 | target is. Yeah. And I guess in this case, the target is itself.
00:48:35.640 | Yeah, the target is since we don't specify a target, the
00:48:38.280 | default target is going to be the div itself.
00:48:40.440 | And just to come back to your last thing, you said also that
00:48:43.040 | the default swap is the inner HTML. So this is going to be
00:48:46.400 | swapped out.
00:48:47.080 | Exactly. Okay. And then the trigger here is load. And that
00:48:51.480 | is, unfortunately, that is not a standard. But I just I couldn't
00:48:55.880 | resist making a specific event called load.
00:49:01.680 | Okay, so you've got HTMS events here. And we can scroll through
00:49:06.520 | them to see there's quite a few events. And here is yeah, load.
00:49:10.400 | Yeah, this is actually if you go to the docs, it's not I don't
00:49:14.800 | think it's this is a this is triggered when an element is
00:49:17.680 | loaded. But it's in the docs I mentioned. And if you go and
00:49:22.680 | look on htmx.org slash docs,
00:49:28.640 | there's a there's a section on events.
00:49:31.520 | Oh, actually, well, if I go to trigger, I guess that would be
00:49:34.760 | the best way. Yeah, it's probably in there as well. Yeah,
00:49:38.360 | there's a couple of special ones in there. Cool. So I'll just
00:49:42.080 | search for load. Here we are non standard events. Great.
00:49:47.720 | Yeah. So we have load we have revealed and intersect revealed.
00:49:53.320 | And like, have you ever worked with the intersection observer
00:49:57.200 | in JavaScript? No. Okay. The the way JavaScript handles sort of
00:50:05.120 | like things scrolling into view is pretty complicated. And I
00:50:09.920 | wanted to declare the API. And so I just kind of put and the
00:50:13.520 | same with loading uses, I forget the name of the event. It's a
00:50:16.560 | big, ugly name. And so for these three things, I was like, look,
00:50:20.760 | I'm just gonna have like my own obviously named events for this
00:50:24.560 | stuff. And we'll, we'll just have to deal with it. And so
00:50:27.920 | make sure I kind of clarify both myself and for other people are
00:50:32.160 | just confused. There's two of these two different load events
00:50:36.880 | htmx colon load versus Yeah, this load.
00:50:40.280 | Anything that starts with htmx colon is an event that htmx
00:50:45.800 | itself triggers as a custom event. Yes. These are these
00:50:50.280 | these three events are synthetic events that htmx makes work as
00:50:55.040 | if they were real DOM events. Okay.
00:50:57.400 | htmx colon load before. Because like I like to set up things so
00:51:04.640 | that when I'm working with a JavaScript library, that when
00:51:08.160 | htmx adds something to my page, the JavaScript library can run
00:51:12.240 | on that as well.
00:51:12.920 | Exactly. Yeah, that's exactly what it's useful for. So maybe
00:51:16.840 | not the best name in the world, but it is what it is.
00:51:19.280 | Okay, well, this is pretty straightforward, then, isn't it?
00:51:21.200 | So you've got this div targeting itself. And when it's Yeah, when
00:51:25.760 | load is done, it's going to go ahead and stick the graph in
00:51:29.800 | here.
00:51:30.280 | Yeah, exactly. And that's so this can be very, a very good
00:51:34.160 | way. Like if you have a part of a web page that is expensive to
00:51:38.000 | compute, and it's making that web page, the first paint of
00:51:41.280 | that web page very slow, you can just move that that chunk out to
00:51:45.520 | a new URL, and then use this pattern. And then suddenly, that
00:51:48.880 | web page will load very quickly. And you know, the other stuff
00:51:52.160 | will come in when it's ready, but the user can still interact
00:51:54.640 | with the page, they can still click on links, or if they get
00:51:57.320 | sick of waiting, or whatever, they're not stuck there waiting.
00:51:59.960 | Like we were for that search result on Stallman's page, just
00:52:03.600 | wondering when this was ever going to come back.
00:52:05.640 | Right. Exactly. So okay, great. I, I wanted to just maybe show
00:52:16.040 | folks how then all this works together with, like, CSS and
00:52:27.040 | JavaScript and, and all that stuff, because like something
00:52:30.360 | else that I found interesting is how the fact that HTMX removes
00:52:36.640 | those four constraints doesn't really impact at all, how I use
00:52:44.040 | styles or JavaScript, you know, right. So like, I'll just share
00:52:52.200 | a couple of things. You know, to maybe make that more clear for
00:52:57.680 | folks. So for instance, the other thing I found interesting,
00:53:04.520 | Carson is like, combined with fast HTML, and also combined
00:53:10.040 | with this really nice deployment service, we've been using
00:53:13.760 | called Railway, where you can run as many things as you like,
00:53:18.720 | and they cost two or three cents a month, you know, unless lots
00:53:23.000 | of people are hitting them. And so there was this interesting
00:53:25.560 | thing where I wanted to create this little mini page, you know,
00:53:29.760 | where I talk about things like HTMX and HTTP and memes and
00:53:35.600 | stuff. And I, what was wild to me as I started doing this was
00:53:40.800 | I like realized, I kind of created this thing, which has
00:53:45.360 | like all these like little things like this auto updating
00:53:47.880 | kind of side and like things that wave over when you go over
00:53:52.280 | them and they're very bold. It's like, oh, like some blogging
00:53:56.040 | content framework and I'm like, actually, no, you know, this is
00:53:59.800 | just a fast HTML page. The source code for this page is
00:54:07.680 | like, you know, it's just marked down with like a tiny bit of
00:54:12.520 | code. And all the work happens actually, in Bootstrap, you
00:54:19.000 | know, right. And so like, with Bootstrap, you know, I was able
00:54:26.640 | to basically create this tiny little thing for this page,
00:54:30.960 | probably here, called like a Bootstrap page, you know, so
00:54:35.400 | overview basically says return a Bootstrap page, it's page
00:54:40.160 | number zero. So that's why it knows which one to make bold.
00:54:42.640 | This is the title of it. These are the sections like there's
00:54:46.000 | all these nice little things in HTMX. Like, if you return a
00:54:49.080 | title tag, as one of your partials, it actually changes
00:54:52.400 | the title of the page, which is sweet. You know, like what's a
00:54:56.720 | section? Well, section is just like, you know, just a div, you
00:55:02.040 | know, with, so like, all the CSS is just really normal. And then
00:55:10.440 | like the JavaScript, and I think this is the bit people get the
00:55:14.000 | most confused about, is also really normal. So if you look
00:55:24.480 | at, you know, we have fasthtml.js, for example, for
00:55:32.120 | markdown, if you create, have a marked class on anything, and
00:55:37.520 | then you basically add a markdown.js component to your
00:55:41.960 | page, then it runs a bit of JavaScript. And now all of your
00:55:45.760 | markdown is automatically done. Or, you know, you can do the
00:55:47.840 | same thing for highlight to get syntax highlighting, or my
00:55:51.520 | favorite ones, sortable. Yeah, this one like, actually, I much
00:55:59.200 | prefer my version, because it's less clever than yours. It's
00:56:02.360 | much easier to see. This is my version of sortable. That's the
00:56:05.080 | entire thing, is you just got sortable create. And so it's
00:56:12.840 | down there, drag and drop. Yeah, you end up with this, this
00:56:17.600 | ability to drag and drop. And the cool thing is that behind
00:56:21.440 | the scenes, it's telling the server what the new order is.
00:56:26.600 | Yeah, yeah. So yeah, this is a great example. Like, you know,
00:56:32.560 | sometimes I've heard a lot, especially now that htmx is
00:56:35.280 | getting more and more popular. And the JavaScript community
00:56:38.920 | can't ignore it anymore, or make fun of it like they used to, is
00:56:42.640 | people say things like, oh, htmx is for people who hate
00:56:46.240 | JavaScript. And there's some truth to that. Obviously, if
00:56:48.480 | you're not a big JavaScript fan, htmx can give you a lot of oomph.
00:56:53.520 | But also to really to take advantage of htmx, like the
00:56:57.520 | events, the fact that it uses events and integrates, like with
00:57:01.040 | the DOM via events, means that it should be able to play very
00:57:05.520 | well with JavaScript.
00:57:06.480 | So like, let's run this little, so I've got this kind of like
00:57:10.480 | idiomatic app I've created with like, most of its comments, you
00:57:15.080 | know, and so like, you know, here's the bit, here's the bit
00:57:18.440 | that makes it drag and drop. Describes how that happens. And
00:57:24.000 | so if we run it, and then I say like, okay, let's show
00:57:32.240 | prioritization, drag it to the bottom. Missed, drag it to the
00:57:36.520 | bottom. There we go. And if I now refresh, it's still at the
00:57:43.600 | bottom. And yeah, it's magic, you know, and like the, like,
00:57:49.240 | how does that work? It's like, I think this is really
00:57:52.160 | interesting. It's like, okay, well, we include this library,
00:57:54.440 | which as we described, is literally three lines of code.
00:57:58.240 | And I added this tiny thing, Carson, which is just a little
00:58:01.280 | JavaScript thing that just basically does a htmx for each
00:58:05.640 | onload kind of thing. So it causes this to happen on all new
00:58:10.640 | things as well. And then sortable, it's kind of amazing
00:58:17.240 | how all these things you made just come together. So we have a
00:58:19.880 | form. And so the to do list itself is actually inside a
00:58:23.440 | form. And so that form is triggered by the event that the
00:58:28.360 | sortable docs say is triggered, which is the end event. I
00:58:33.000 | didn't have to do anything. And then it just calls slash
00:58:36.640 | reorder. You know, and then reorder is two lines of code,
00:58:42.280 | you know, it updates each to do to the new priority and returns.
00:58:46.560 | This is the reason my code simpler than yours is because
00:58:48.800 | it's less efficient. I returned the whole to do list. You know,
00:58:52.000 | it was just fine. Yeah. So sometimes that's the right
00:58:55.320 | thing. JavaScript is such a delight in htmx, because I only
00:58:59.520 | have to use it for the bits I need it for, you know, right.
00:59:02.600 | And that's so you know, I say htmx is pro JavaScript because
00:59:06.440 | of that, for that very reason, it takes the pressure off of
00:59:09.440 | JavaScript to be the entire infrastructure for your web app.
00:59:12.920 | And so it can be used for these situations where it really can
00:59:16.400 | add a lot of value. So drag and drop is something that's not
00:59:18.920 | baked into the web out of the box, at least not well by
00:59:22.440 | default. And so these, you know, sortable JS addresses that and
00:59:26.320 | provide some really good functionality. And then htmx can
00:59:28.800 | integrate with it via events really cleanly. So a really
00:59:32.720 | that's a another great example. I think of htmx being being used
00:59:37.480 | the way it was intended to and sort of playing well with other
00:59:39.840 | things, you know, it's designed to be, especially with it's a
00:59:43.000 | focus on events, it's designed to plug in reasonably well with
00:59:47.280 | other libraries, as long as they, you know, as long as they
00:59:50.120 | play well with the DOM to triggering events, and then
00:59:53.360 | using inputs to communicate information out to the remote
00:59:58.600 | systems.
00:59:59.480 | So let's switch topics a bit if we can. And the reason that I,
01:00:06.880 | or a reason I use the much unappreciated epithet, genius is
01:00:12.440 | because the most things that I come across, and I say, like,
01:00:16.480 | that's clever, I can immediately think like, oh, I see exactly
01:00:20.720 | how they came up with that, you know, but like, my friend, Chris
01:00:24.120 | Latner, for example, who's created like LLVM and Mojo and
01:00:28.520 | Swift and other things, like, very often I have conversations
01:00:32.320 | with him, where he describes the thing he's created. Having
01:00:36.480 | described the thing, I can say like, yes, that is the right way
01:00:39.800 | to do that. And then I'm like, but I don't know how you could
01:00:43.360 | possibly have known that I only know it now that you've told me
01:00:47.480 | now this thing you've done, like, there are four constraints,
01:00:50.560 | we can remove them with a polyfill. Once we do that, we
01:00:53.320 | can reprogram the web. Like, where did that come from?
01:00:58.400 | Because like, this goes back to like, like 10 years plus ago
01:01:02.040 | that you kind of first implemented this. And I hadn't,
01:01:06.760 | I've not seen it.
01:01:08.000 | Yeah. I mean, there were, you know, there was a there was
01:01:12.400 | something called pjax back in the day. I don't know if you
01:01:15.120 | ever heard of pjax. Yeah, there was pjax. And then there was a
01:01:21.560 | in jQuery, there was this I think it's called fetch, or
01:01:25.120 | load, load, I think it's a load. And it does something similar,
01:01:30.400 | you give it a view, you just give it a CSS selector, like in
01:01:34.040 | the dollar sign syntax, and then you say dot load, and you give
01:01:36.760 | it a URL, and it'll issue a get and just load the response into
01:01:40.040 | that thing. Yeah. And so there were some, there were some
01:01:43.240 | little things like that floating.
01:01:44.680 | Yeah, well, we were one of the first jQuery users when it first
01:01:48.840 | came out, actually. And so it was fun to watch those things
01:01:51.600 | kind of get added. And definitely Risik, Risik's a
01:01:54.720 | genius. You know, yeah, for sure.
01:01:56.640 | Yeah, he's, oh, yeah. And so I think, like, you know, I saw
01:02:01.320 | that, I've told the story before, but I was just having
01:02:04.080 | trouble with a performance issue. I was trying to do
01:02:06.160 | sorting in JavaScript, in like 2009, or eight. And it just was
01:02:11.320 | too slow, because the runtimes at that time were so slow, and
01:02:14.840 | non standard and all the rest of it. And so DOM manipulation was
01:02:17.960 | very slow. And I ended up, I don't know if I use the jQuery
01:02:23.360 | dot load method, but I did something, I think I might have
01:02:26.920 | seen it and did something similar, and then kind of
01:02:29.320 | started making that more general using the jQuery AJAX function.
01:02:35.040 | Where, you know, I was like, Oh, yeah, I didn't. So I had a UI,
01:02:40.120 | I was trying to sort, it was too slow to do in JavaScript. And
01:02:42.600 | out of desperation, I tried doing it on the server side, and
01:02:45.440 | then just slamming it into the UI. And that turned out to be
01:02:48.840 | really fast. Like, to my surprise, it was pretty desperate
01:02:52.080 | move on my part, I didn't think I was gonna be able to do it.
01:02:54.040 | Well, but, but it worked. And I was like, Oh, this is great.
01:02:57.960 | Okay, I didn't know you're allowed to do that. You can just
01:03:00.480 | put right, you know, you put HTML wherever you want. That's
01:03:02.720 | cool. Yeah. And, and then so that turned into like a little
01:03:07.000 | function that I had for a while that was kind of more in the
01:03:09.840 | jQuery style of like, you look things up and hook in
01:03:12.920 | functionality. And then I saw Angular one. Yes, I didn't like
01:03:18.080 | I didn't like much of Angular one, except that they use
01:03:21.200 | attributes to specify behaviors. Yeah, I was like, you know, this
01:03:24.480 | is, this is a lot like, like the href stuff, like links and
01:03:28.400 | big hit YouTube video was an angular. Okay, yeah. Yeah, I
01:03:33.000 | don't want to throw it through. I don't want to throw any shade
01:03:36.240 | at Angular. I've got no beef with Angular, and it's fine. But
01:03:39.240 | it wasn't what I was looking for. And what I was trying to
01:03:42.040 | do, but I did like how they use attributes. And I realized,
01:03:45.200 | okay, I can use attributes to hook this behavior in instead
01:03:50.160 | of instead of using a jQuery selector. And, and so that sort
01:03:56.680 | of turned into that just very organically turned into
01:03:59.280 | intercooler.js. And I've got to be honest with you, like a lot
01:04:01.880 | of the academic stuff came afterwards. Yeah, I didn't
01:04:04.800 | understand hypermedia very well. Yeah, when I did when I
01:04:07.880 | initially did all this stuff. It was just, you know,
01:04:11.080 | look, that's that doesn't shock me at all. You know, my, my
01:04:14.440 | friend and co founder, Eric Reese wrote this book called
01:04:18.400 | the lean startup, which is actually a lot more than just
01:04:21.200 | about startups, you know, this idea of the MVP. And it's
01:04:25.320 | actually the basis on which answer AI is created, which is
01:04:28.280 | building things that way, which is like, iteratively, bit by
01:04:33.000 | bit, you know, and then later on, you kind of look back and
01:04:35.360 | you're like, Oh, I kind of built something kind of cool here. I
01:04:38.480 | wonder how this thing I built actually works. And then you're
01:04:41.760 | like, Oh, I guess it's hypermedia. And I guess it's
01:04:43.680 | actually these four constraints, we actually ended up removing
01:04:46.120 | them. And yeah, I think it makes it less intimidating to know
01:04:50.280 | that you don't have to invent this new universe in your head
01:04:54.280 | all ahead of time, and then implement it. Yeah.
01:04:56.760 | Yeah, you know, there's what's the saying, like, existence
01:05:00.840 | brings essence into being like, you have to do the thing first,
01:05:04.000 | and then you can talk about what the thing is. Yeah, it's kind of
01:05:07.200 | got to be there first. And then you can say, Okay, what what
01:05:09.920 | just happened?
01:05:10.520 | You must have had some kind of intuition at some point that
01:05:15.000 | there was a direction forming that felt like you were enthused
01:05:20.480 | enough about it, you wanted to invest in.
01:05:22.480 | Yeah, I you know, to me, it was more just an unwillingness to
01:05:27.120 | deal with the complexities of like, you didn't knock out JS at
01:05:30.520 | the time. And, and things like that. I just, I was like, man, I
01:05:35.200 | just don't want to deal with all that. No, I just, I just, I just
01:05:38.760 | want to be able to put stuff in the DOM. And, you know, I think
01:05:43.000 | when I first did it, I went through there was a within this
01:05:46.760 | is with the intercooler, the predecessor to HTMX, which is
01:05:49.240 | very similar. It's just it's basically a jQuery
01:05:52.000 | implementation of the same stuff that HTMX does. I went through
01:05:57.080 | and I started doing examples. And then I started realizing
01:06:00.560 | like, whoa, you can do infinite scroll with this. Whoa, you can
01:06:03.360 | do active search with this. Like, yeah, this is cool. You
01:06:05.720 | can do a lot with this. And so that, but that was, I discovered
01:06:09.800 | that, you know, I didn't think about that up front, I discovered
01:06:13.000 | the fact that, hey, with these abstractions, you know, with the
01:06:17.000 | limitations on HTML removed, you can actually do a lot of cool
01:06:21.240 | stuff. So yeah, it was very organic. And I definitely not
01:06:25.040 | like me thinking things through.
01:06:27.840 | Yeah. So, no, I mean, it's, it's interesting to me, because I'm
01:06:34.720 | sure I've never created anything as clever as HTMX. But I've
01:06:39.080 | definitely created things that are at least as bloody minded as
01:06:44.120 | HTMX, you know, like you've kind of been like, you know, it's
01:06:48.840 | interesting, you mentioned Knockout, for example, most
01:06:50.800 | people listening probably won't remember it, but it was very
01:06:52.720 | popular back in the day. And it came out as, as we were building
01:06:58.120 | Kaggle, which is one of my earliest startups, and some of
01:07:00.400 | the folks were like, we've got to do Knockout. And I was just
01:07:03.120 | like, we just so don't have to do Knockout. And yeah, it's
01:07:07.560 | interesting, you have this reaction to complexity. It's not
01:07:13.720 | a reaction to like, it's not a kind of classic conservative,
01:07:17.320 | like, we have to do things the same way. It's more like, no, we
01:07:22.440 | have to make things accessible. And we have to, like, you know,
01:07:27.840 | appreciate what's good about what exists and take advantage
01:07:31.000 | of that. But yeah, it's interesting. Like, I feel like
01:07:35.040 | maybe, like I said, at the start of this interview, you don't
01:07:41.520 | look or sound like a tech genius, you don't live in a
01:07:44.520 | place full of tech geniuses, you know, you're, you know,
01:07:47.640 | and I'm also not a tech genius. So it all checks out.
01:07:51.880 | Teaching kids baseball, you know, like, you, you know, and,
01:07:57.960 | you know, so I guess, you know, I would consider myself an
01:08:01.280 | outsider, you know, would you kind of consider yourself an
01:08:04.920 | outsider? And would you say that's part of why you can
01:08:07.320 | create these somewhat bloody minded things that push back
01:08:11.240 | against what everybody else is trying to do?
01:08:13.040 | Right? Yeah, I definitely was an outsider in the Bay Area,
01:08:17.200 | because I was from Sacramento. And I've been like one thing I
01:08:21.080 | realized about my, my, particularly when I was younger,
01:08:24.280 | as I was very naive about, like, everything, pretty much
01:08:27.800 | everything. And so, you know, the problem with being naive is
01:08:31.880 | when bad stuff happens, you can get pretty embittered. And so I
01:08:35.720 | went through that whole naivety, embittered cycle on the Bay
01:08:38.880 | Area, and so forth. And so, so there's definitely
01:08:43.160 | some people who don't know. So Sacramento is like, three hours
01:08:47.560 | or so inland of San Francisco, and it's like, it's pretty
01:08:50.840 | hot. And pretty kind of like, it's not. It's not at all like
01:08:56.000 | San Francisco.
01:08:57.080 | Yeah, it's very agricultural or was it's the Central Valley is
01:09:01.400 | filled up because the Bay Area has gotten so expensive. So what
01:09:04.720 | I grew up in has been is very different. Now, the area I grew
01:09:07.920 | up in, but, but yeah, I was just not, you know, I just wasn't a
01:09:11.400 | barrier person. And I felt that like the entire time was there,
01:09:14.400 | even when I went to Berkeley and Stanford for grad school, and
01:09:17.600 | just was very much an outsider. And that's fine. I'm also, you
01:09:22.440 | know, a little bit of a contrarian, I guess. And so
01:09:25.240 | that, you know, and that's good and bad, you know, it's been
01:09:28.240 | good parts of my life and bad and of course, but I do think
01:09:31.960 | like something you sort of touched on there is there
01:09:34.960 | doesn't, in tech, tech, technology is so forward
01:09:38.240 | looking, that we don't do a lot of looking back at what people
01:09:42.520 | had before, right, or what was done before. And I think that's
01:09:46.120 | one reason why we're constantly reinventing the wheel, you know,
01:09:49.000 | in many ways, sometimes worse, you know. And so the with with
01:09:56.120 | HTMX, and with intercooler before that I really was trying
01:10:00.840 | to once I understood once I got my feet under myself and
01:10:03.120 | understood what was going on, is I tried as much as possible to
01:10:06.920 | rhyme, you know, that's the way I would say it is, you don't
01:10:09.680 | have to be the past, you don't have to dress or like, you know,
01:10:12.960 | act or whatever. But like, if you can rhyme with that stuff,
01:10:16.440 | like, there's probably some good ideas there. And I think that's
01:10:18.440 | one reason why HTMX has a pretty high power to weight ratio is
01:10:22.240 | that it just builds on these really, like CSS selectors, and
01:10:26.320 | like the basic DOM APIs and events, like, you know, the, the
01:10:30.480 | DOM being an event bus, like, that's, those are all concepts
01:10:33.720 | are already there. And HTMX really just like, is built on
01:10:37.360 | top of them. I mean, that's why I think
01:10:39.920 | I spent months, a year or two ago, teaching people, APL
01:10:45.720 | notation originally developed in the late 50s. Yeah, like, I
01:10:49.960 | definitely appreciate this idea of recognising when really deep
01:10:57.200 | thoughts have been had in the past. And when you can take
01:11:00.840 | advantage of that. Yeah, present and combine them with new
01:11:04.680 | things.
01:11:05.160 | Yeah, like, what's a new take on that? You know, that's that can
01:11:08.880 | often be one example I bring up a lot is the visual basic six
01:11:12.960 | debugger was like the best debugger I ever used to continue
01:11:17.160 | so good. Yeah, you can it was like, you could do whatever you
01:11:20.600 | wanted. You could drag the program count, like you could
01:11:22.520 | drag the pointer wherever you wanted to during execution. It
01:11:25.160 | was unbelievable. And my understanding is dotnet has that
01:11:28.200 | now, but I work on the JVM a lot. And it's got nothing like
01:11:31.160 | that. Nothing close. Yeah. And it's like,
01:11:33.640 | and if you look back to get back, if you go back further to
01:11:37.080 | Microsoft Access, you know, the thing it had with these like
01:11:40.680 | reports and stuff was basically flex grid, you know, HTML
01:11:45.280 | programmable back and I was doing that, I guess, in the
01:11:49.000 | early 90s. Let me just again, switch then to kind of like
01:11:53.320 | talking about something which I've seen with you, and I've
01:11:59.280 | certainly experienced myself. I very intentionally do a lot of
01:12:03.920 | things extremely differently to everybody else. Because I like
01:12:08.440 | to experiment with like, what happens when you try things
01:12:11.720 | differently. So I'd be able to think about nbdev, which is
01:12:15.000 | where you do all of your assist software development inside
01:12:19.200 | Jupyter Notebooks. And I've written most of my software like
01:12:21.560 | that for the last few years. And it turns out, the affordances
01:12:24.600 | provided in notebooks are actually amazing. I've, you
01:12:30.560 | know, I've created an AI thing called fast AI, which kind of
01:12:34.600 | when everybody was trying to build big foundation models, I
01:12:37.360 | was focused on like fine tuning. And now with fast HTML, when
01:12:41.880 | everybody's focused on Svelte, React, Vue, whatever stuff, I'm
01:12:47.760 | like, let's lean into HTMX and hypermedia and Python instead
01:12:52.720 | of JavaScript. Something I've noticed a lot is, and I've seen
01:12:59.200 | there's a psychological phenomenon, where when human
01:13:03.600 | beings are presented with change, there's like literally
01:13:07.800 | a chemical reaction in their brain that is identical to
01:13:10.600 | physical pain. And I see that with how people react to HTMX as
01:13:18.080 | well, which is I often see people respond with an enormous
01:13:22.480 | amount of anger. You know, almost like this kind of
01:13:27.520 | desperate anger. And yeah, I'm kind of like, and so it's
01:13:30.720 | interesting how, what, you kind of have these two really
01:13:36.600 | different directions. One is like, you're literally a
01:13:38.600 | university professor, like you say, expertly Stanford, and you
01:13:42.560 | create these like, incredibly academic things, looking back
01:13:46.640 | at Roy Fielding and HATEOAS and everywhere else. And then
01:13:50.120 | there's the other Carson, which is like, trolling, memeing, you
01:13:54.800 | know. I guess like, yeah, it's like, is it like, partly that
01:14:01.160 | you're kind of reacting to the bullshit earnestness of this
01:14:07.160 | world and trying to like, not take it too seriously? Or like,
01:14:10.120 | is it kind of like an intentional thing you're doing
01:14:12.080 | to try to deal with the reaction people are having to this
01:14:16.560 | psychological pain of seeing change? Or, you know, what's
01:14:20.000 | the yeah, how do you see all this?
01:14:22.280 | I will. So I think you're right. And I'm sympathetic. There's a
01:14:26.040 | reason we're like that, right? Like, there, there's nothing
01:14:29.320 | about us that is not there for, for some reason or other. And
01:14:32.720 | so change is hard on humans. So we should make, you know,
01:14:35.720 | allowances for that fact. Humor is for me, I've always been kind
01:14:41.400 | of a joker, and last clown and so forth. And I grew up on the,
01:14:46.840 | you know, on the forums in the late 90s and early 2000s, kind
01:14:50.880 | of pretty rough and tumble back in the day. And so I got I got
01:14:55.520 | good with memes. And I just always preferred joking. It's
01:15:00.080 | funny, you know, I just I don't know, I end up like a lot of
01:15:06.160 | memes. And, you know, I think they're, there's, they're good.
01:15:09.960 | They're, you know, a picture is worth 1000 words, and I mean,
01:15:12.840 | maybe worth like 100,000 words, like a good meme, and really got
01:15:17.280 | through a lot of stuff. And so that's it. That's one. That's
01:15:22.920 | one by Alex. That's pretty funny one. So I really like humor.
01:15:26.720 | So like, it's so on point, like, like, it's literally what we're
01:15:31.720 | talking about. It's like, I was like, hey, if you do this stuff,
01:15:35.440 | you're just doing the foundations. And you keep doing
01:15:38.960 | the foundations, and they all come together. And suddenly
01:15:41.920 | you're like, you're really good at building web apps, you know,
01:15:45.960 | yeah. And like, you know, Daniel Roy Greenfield, one of the
01:15:51.480 | co authors of two scoops of Django, which is one of the best
01:15:54.320 | programming books of all time, within 45 minutes of trying fast
01:15:58.520 | HTML, and he'd never also used HTMX, he had rewritten his
01:16:01.480 | entire blog system. Yeah, his his wife, Audrey, the other of
01:16:07.040 | the two scoops of Django co authors saw him do that. The
01:16:12.880 | next day, she was doing a hackathon. She had never used
01:16:17.320 | fast HTML before she decided that morning that she was going
01:16:20.280 | to use it for her team in the hackathon. They won the
01:16:22.480 | hackathon. You know, like these people who have like learn the
01:16:26.480 | basics, and then they get something that rhymes. Yeah,
01:16:29.880 | they zoom in. But so these memes, they're like, they're
01:16:35.240 | funny, but my god, they're like, they're cut to the bone as well.
01:16:39.960 | You know, yeah, yeah, I think I'm pretty good writer, you
01:16:42.960 | know, the book, I was actually better at English, like I scored
01:16:48.480 | better in standardized tests on on English than I did on math.
01:16:52.680 | And I've always just liked, you know, I like I read a boatload
01:16:57.360 | when I was a kid. And so I, you know, I just, it's just a knack
01:17:01.120 | I've got for me. I don't know. It's not this isn't Shakespeare,
01:17:04.120 | but it's very effective communication medium, combining
01:17:07.680 | a picture with a, you know, with a short and pithy statement. So
01:17:12.520 | well, I mean, when I wanted an explanation for HTMX, I, I used
01:17:22.560 | to I used one of the memes because it is, yeah, it did a
01:17:25.640 | better job of explaining what was in my head, I could use
01:17:28.480 | words for which is like, yeah, and actually, so Eric reason I
01:17:31.320 | were talking about the kind of days of when we were starting
01:17:34.920 | coding PHP, you've got a shell home directory, you dump a file
01:17:39.880 | in there, you've got a web app to show to your friends, you
01:17:42.520 | know, and so it was even simpler than like your 2004 model. And
01:17:48.360 | yeah, you know, we were both saying like, Oh, you know, it's
01:17:51.480 | so painful to create an application now, right, you
01:17:54.960 | know, and so yeah, the picture does tell 1000 words a day does
01:18:01.320 | it doesn't humor works, people like humor, the people who get
01:18:04.960 | mad about them, like they're probably the people that you
01:18:07.080 | want to get mad anyway. So, you know, I don't know, it's been a
01:18:12.200 | good way. I've gotten much better, though, like, you know,
01:18:14.200 | if you if you were talking to me 10 years ago, I would have been
01:18:16.520 | much more embittered about things like much more
01:18:18.920 | sarcastic, you know, there's, and there's a part of me that's
01:18:21.640 | still like that. I just really, you know, I was about it was
01:18:25.480 | about 10 years ago, I just kind of was like, you know what, I
01:18:27.800 | can't live like this. Like, I'm not I ever got to be more
01:18:31.000 | positive about things. There's a lot of good things. It's so
01:18:33.640 | easy to be negative. And, you know, especially with the
01:18:36.920 | information overload we have now. And I you know, I just was
01:18:41.560 | I just sort of committed to being more positive about it.
01:18:43.640 | And so
01:18:43.920 | to does it help to be away from the Bay Area, you know, living
01:18:48.280 | in rural Montana,
01:18:49.720 | probably it's, there's less financial pressure. That
01:18:53.120 | certainly helps. You know, Montana is very beautiful. And
01:18:56.680 | like, there's a lot of nature also, you can freeze to death.
01:18:59.360 | So that gives you some perspective on life, like, Oh,
01:19:02.480 | wow, it's minus 40 outside. I don't know. I really hope the
01:19:04.960 | power. I really hope that the minus 40 Fahrenheit, I really
01:19:08.640 | hope that the power doesn't go out, because that would be bad.
01:19:11.520 | So you know, I think that helps. But I think, you know, when I
01:19:16.440 | look back, I think I could have handled the barrier much better
01:19:19.000 | than I did. If I had just been a little bit more, just been more
01:19:22.840 | positive, you know, early on, it was early on, what do I want to
01:19:26.400 | say, you know, for a long time, to me, people who were sort of
01:19:29.320 | Pollyannish were, like, I just would, you know, like, Oh, that
01:19:33.560 | person's just positive. My role is fake. And now I'm much more I
01:19:38.000 | tried to be much I tried to be almost fake positive, because
01:19:40.680 | it's not going to change so much is not going to change anyways.
01:19:43.160 | Right. So like, yeah, you know, you can control your, like,
01:19:47.080 | there's a lot of stoicism, I can't handle stoicism, because
01:19:49.920 | it's often very sort of like, morose. And I just can't be like
01:19:54.640 | that. And so I like the more Joker.
01:19:57.240 | I think also, like, it, like, I've always felt like, the
01:20:03.160 | internet's a big place, you know, and I always feel like my,
01:20:06.400 | my job is not to market my weird shit to other people. But to
01:20:12.720 | find the other people who appreciate my weird shit, and
01:20:15.880 | let them find me. And so then you end up with a community of
01:20:19.360 | people who appreciate your weirdness, and you don't have to
01:20:23.880 | spend time trying to convince people to do something they
01:20:25.680 | don't want to do. Yeah, well, and that's, you know, I didn't
01:20:28.800 | know this was gonna work as well as it did. You know, I had, like
01:20:32.360 | a year ago, we basically, you know, we were gonna release the
01:20:35.960 | book, and I've been messing around on Twitter a little bit
01:20:38.480 | more, I'd taken some time off Twitter, because it just gotten
01:20:41.760 | so crazy. And so, but I came back and I was like, and I about
01:20:46.920 | a year ago, I committed, I was like, Okay, I'm gonna really
01:20:50.240 | like, I'm gonna engage on Twitter. And I'm just gonna go
01:20:53.680 | crazy and be like the crazy person that I want to be on
01:20:56.960 | Twitter, and have fun with it. And if that works, great. And if
01:20:59.960 | it all goes down in flames, also great, like, I don't care. And I
01:21:03.920 | think so, you know, there's probably some authenticity
01:21:07.360 | there. But there's also a bunch of risks, like, you know, this
01:21:10.400 | could all end in tears, probably will. But, you know, I just, I
01:21:15.800 | don't know, I just I really, I tried, you know, I gave that
01:21:18.800 | talk to big sky DEV CON, where I talked about trying to be more
01:21:21.040 | positive. And I think that's been the big change for me.
01:21:24.040 | About 10 years ago, I just was like, I need to be more positive
01:21:27.160 | about things. Yeah, still be a joker, still be myself. But
01:21:30.560 | just don't emphasize the negative stuff so much. Don't
01:21:34.120 | go on it so much.
01:21:34.960 | No, I mean, you can find like, you can be you'll continue to be
01:21:38.960 | authentic whilst finding different facets to highlight
01:21:43.680 | internally and externally. For sure. Yeah. Yeah. We all have
01:21:48.160 | those facets. Right? I'm not sure I can recommend what I did
01:21:52.520 | for other people. But it worked. It worked this one time anyways.
01:21:56.960 | So, you know, I guess the thing I'd be interested to kind of
01:22:04.080 | wrap up on unless there's other stuff you feel like is worth
01:22:07.520 | talking about is like the kind of where to now, you know, if it
01:22:14.040 | seems to me, you've highlighted how browsers ought to work. I
01:22:20.920 | don't see any reason they shouldn't work like this. And in
01:22:24.800 | fact, if this stuff was built into the browser, you wouldn't
01:22:28.880 | probably need the HX dash pieces, you know, maybe some of
01:22:32.800 | it could be have a bit of a streamlined developer experience
01:22:37.960 | in ways that you couldn't do. I guess like, I mean, not that it
01:22:45.400 | feels like a matter hugely to me, if whether that happens or
01:22:48.560 | not, I don't mind sticking an HTML script to the top of my
01:22:50.960 | pages. And in fact, fast HTML adds that script header by
01:22:53.680 | default. But yeah, I guess I'm curious about like, what's,
01:22:57.400 | what's in your head now? Are you thinking like, there's other
01:23:03.800 | things I could do with this? Are you moving on to something
01:23:06.360 | else? Are you feeling like you know, your, the browsers might
01:23:11.280 | actually pick up on some of these ideas, you know?
01:23:13.600 | Yeah, well, I think, I think we'll, I know that the browser
01:23:19.080 | people are looking at HTMX and are interested in the idea. It's
01:23:22.560 | a big process to get anything like that into the browser,
01:23:26.280 | especially coming from more of an external source than sort of
01:23:29.720 | the internal, you know, sources.
01:23:31.960 | And also the most important bit, the fourth one, the like, update
01:23:35.240 | any part of the DOM that feels like it would be hardest to
01:23:38.960 | Yeah, yeah. So there's, there's already, it's kind of there a
01:23:44.280 | little bit, you can actually, there's a target attribute on
01:23:47.280 | anchors and forms. And that takes an ID, but the ID has to
01:23:51.440 | be of an iframe. So nobody uses it. So there's like, there's the
01:23:56.960 | infrastructure is there, it's like almost there. So I don't
01:24:00.360 | think it's, I don't think it's too far of a jump. And one of
01:24:03.200 | the HTMX team members is working on a more formal proposal to get
01:24:07.080 | some of these ideas, not the full HTMX API, but some of these
01:24:10.440 | ideas, and HTML. And you know, I mean, it could happen. That
01:24:14.880 | would be a very long term process. I do think HTMX is
01:24:18.320 | pretty much done as far as like what it does, and the API
01:24:21.840 | provides, if new technologies come out in the browser. So for
01:24:25.880 | example, the transitions API came out, and we integrated that
01:24:28.720 | into HTMX. So I would expect to, you know, do some things like
01:24:33.240 | that, as browser technologies improve, but I don't think HTMX
01:24:37.240 | is going to change a whole bunch, just fixing bugs and, you
01:24:40.400 | know, improving it, hopefully not. At this point, I want to
01:24:44.680 | not ruin it. Like, let's I'll put it that way. So I'm going to
01:24:47.880 | try and keep it pretty stable. And people
01:24:49.560 | Yeah, it doesn't feel I mean, that's kind of partly what I was
01:24:51.240 | asking. It feels like it almost feels like you discovered
01:24:56.280 | something. You know, you discovered the thing, and you
01:25:00.080 | should, you know, and then you show the people the thing, and
01:25:02.160 | then you've written down why the thing's good. And you've
01:25:04.680 | provided examples of the thing. Like, yeah, dude, where do you
01:25:08.120 | go from here?
01:25:09.160 | Oh, man, what's a well, you know, I've got other projects I
01:25:13.720 | work on. There's, you know, idiomorph, which is sort of a
01:25:16.520 | DOM morphing algorithm that I think was an improvement over
01:25:19.400 | the state of the art.
01:25:20.920 | Okay, well, let's go slowly here. Okay. So htmx, idiomorph,
01:25:26.120 | because I know of this thing. But maybe you could like just
01:25:32.480 | quickly teach me about it. Because it's like, is this like
01:25:38.800 | when you say a DOM merging algorithm? Is this kind of like
01:25:41.480 | what Alexia live view does or something like the thumb
01:25:46.000 | diffing? Like, you should explain maybe from scratch what
01:25:50.400 | basically, the fundamental problem and the original
01:25:53.840 | library. Yeah, well, I mean, the original, the original problem
01:25:58.640 | is, you've got a DOM, which is a tree of stuff. And you've got a
01:26:02.760 | new tree that you need to take this tree and like, change it
01:26:07.000 | into this other tree. And you want to do that with as few
01:26:09.760 | changes as possible. And so that that's called morphing. That's
01:26:14.840 | what the way
01:26:15.400 | you've got that thing with like the Rick Astley video that you
01:26:20.360 | get playing or something is that that's is that one of these
01:26:23.320 | examples?
01:26:23.840 | Yeah, it's not it's not in the examples. But if you go to the
01:26:27.440 | bottom of the idiomorph page, there's there's an example that
01:26:30.760 | shows that. Yes, down there somewhere. So if you watch this
01:26:34.800 | gif, like that top is what basically what happens is if you
01:26:38.920 | if you watch the top, top one, the video keeps playing, or the
01:26:43.000 | top ones resets and the bottom one doesn't. And so like, yeah,
01:26:47.920 | morphdom doesn't work. Yeah, that's
01:26:49.640 | refreshing. Yeah. And so I don't want to get too much into the
01:26:54.320 | weeds on this. But basically, idiomorph is an improvement on
01:26:57.400 | morphdom. It uses something called ID sets to do a better
01:27:00.560 | job of matching up elements when it's trying to
01:27:03.880 | add. So basically, I can return a bigger chunk of a bigger HTML
01:27:10.240 | partial into something where some of what I return is the
01:27:14.720 | same as what was there before. And it won't actually replace
01:27:17.880 | what was there. So to be kind of more efficient, it won't update
01:27:20.480 | the state.
01:27:21.200 | Exactly. It doesn't make mistakes higher in the DOM,
01:27:25.000 | because it has these things called ID sets. So I don't know.
01:27:28.400 | And then there's and then there's hyperscript. Don't show
01:27:31.160 | anyone.
01:27:31.520 | I mean, you say this, because like, you know, a few weeks ago,
01:27:36.240 | I asked you about this. And I was like, should I learn
01:27:37.960 | hyperscript? And you're like, no. And that was the end of the
01:27:41.520 | conversation. And then since then, I've like seen people
01:27:44.560 | using it. I'm like, wait, this looks amazing. Somebody on the
01:27:47.840 | discord yesterday had like, literally like a spreadsheet
01:27:51.040 | written in hyperscript. So I actually want to try it.
01:27:54.480 | That was pretty incredible. Yeah, so hyperscript is another
01:27:57.760 | project. And it's basically a scripting language. So it's an
01:28:03.200 | alternative to JavaScript. And it's based on an old scripting
01:28:08.600 | language called HyperTalk, which was a scripting language for
01:28:11.960 | HyperGuard, exactly.
01:28:13.520 | Which is also what AppleScript was based on, you know, same.
01:28:16.680 | Yeah, AppleScript has given a lot of people a bad taste for
01:28:20.160 | that style of language, because AppleScript is so bad, which I
01:28:23.440 | agree 100%. But it's, it has a lot of interesting features. I
01:28:29.760 | teach compilers, and I like programming languages. And so,
01:28:33.600 | you know,
01:28:34.360 | I enjoyed reading the source code to this, actually, like,
01:28:37.120 | it's, yeah, it's, yeah, I thought like, okay, I can see
01:28:39.520 | you're an academic who you probably must teach this shit,
01:28:42.040 | because it's pretty hardcore. Like, I
01:28:44.960 | yeah, it is. Yeah, it's a it's a standard recursive descent
01:28:49.280 | parser and all that sort of stuff. But you can see like
01:28:51.920 | these things, it's just like on click toggle disabled until,
01:28:54.960 | you know, it has a very English like syntax. And then the really
01:29:00.400 | interesting thing about it, if you go up to the top, go up to
01:29:03.880 | the where's the nav, or excuse me, go to docs is scroll down
01:29:11.400 | on the left hand side, go down to us, keep going, keep going,
01:29:15.800 | what's called keep going. Keep going. Keep going. It's async
01:29:20.800 | transparency. So if you're, if you're, if you're into
01:29:23.520 | languages, this is one thing that's pretty interesting about
01:29:26.560 | HyperScript, which is the it, the way the the runtime works,
01:29:32.400 | like you don't have to resolve promises, the runtime
01:29:35.000 | effectively resolves all the promises.
01:29:37.040 | I hate this. So script code, you know, it just makes me
01:29:41.120 | miserable.
01:29:41.800 | Right. So instead of like this callback style, or doing a
01:29:46.280 | wait, you know, there's a if the thing you're working with
01:29:49.240 | returns a promise, you can do in a wait on it, but then you
01:29:51.360 | have to mark it as a sink and all the rest of it. Like in
01:29:53.880 | HyperScript, you just Yeah, in HyperScript, you just you can
01:29:57.240 | put like, wait one second, and it'll do it does all the stuff
01:30:01.160 | for you. It like it, it waits for that two seconds, and then
01:30:05.200 | starts executing the next thing. And so that's a, that's sort of
01:30:10.840 | a, it's an interesting technical thing. Like, if you scroll down
01:30:14.160 | a little bit further, there's keep going toggle loops, this
01:30:20.080 | one. So this scroll up there, that loop, this is a this. So
01:30:24.560 | one of the neat things about the, the runtime infrastructure
01:30:27.640 | of HyperScript is that you can have event driven loops. So
01:30:31.400 | this, this is, this is a loop that's saying loop until you get
01:30:35.160 | this event. Right. So on click repeat until events stop. And so
01:30:41.080 | and then send and then there's another button that sends the
01:30:43.520 | stop event. So if you click on that, click meet a pulse button,
01:30:46.080 | yeah, it's gonna pulse, and then it'll keep pulsing until you
01:30:50.800 | click cancel. Yeah. Which is when you click cancel event to a
01:30:55.360 | particular element. Yeah, to the previous button. And so it's
01:30:59.160 | sending it to that button. And what's interesting there is that
01:31:01.840 | if you watch the pulse, it finishes it, the pulse finishes.
01:31:06.240 | And that's because it that's because it's in this loop, that
01:31:12.040 | only after the loop is finished as a check, did I receive the
01:31:14.920 | stop event. And so it's like, it's event driven control flow,
01:31:18.680 | which is pretty interesting, like when you're working with
01:31:21.280 | the DOM. So I don't know, this is definitely a passion project,
01:31:24.440 | I have a hard time recommending any, anyone watching this or
01:31:27.880 | listening to this, check it out. But it's got some cool ideas in
01:31:30.840 | it. I know those kinds of projects, like I, I'm a bit the
01:31:34.480 | same with nbdev. You know, when people are like, should I use
01:31:37.560 | nbdev? I'm like, I don't know. I'm like, I like it a lot. I've
01:31:42.000 | written all my software for the last few years. And that, you
01:31:45.040 | know, people keep asking me, how come I'm so productive? And I'm
01:31:47.640 | like, I think a lot of us because of nbdev. But should you
01:31:49.960 | use it? Oh, I don't know. It's pretty weird. Everybody's gonna
01:31:53.640 | think you're weird. Yeah. Right. It's funny, though, like, you
01:31:58.000 | know, this kind of parsing compiling stuff. I happen to
01:32:02.200 | have been lucky enough to have a few friends in my life who, you
01:32:05.080 | know, have, who are amongst the best in the world. They're like
01:32:08.040 | Terence Parr, who created Antler, was a colleague at the
01:32:11.000 | University of San Francisco, and Chris Lattner, obviously, and
01:32:14.560 | then years ago, I, back in the Perl days, I used to spend some
01:32:17.320 | time with Damien Conway on Perl. It's such an interesting space,
01:32:23.360 | you know, like, like, getting down to the hardcore of these
01:32:27.480 | algorithms, and then implementing a language. It must
01:32:29.840 | have been super fun for you just to make this. Yeah, yeah, for
01:32:34.680 | sure. And it's all written in JavaScript. So the parts, it's
01:32:37.880 | all it's all in JavaScript, which is going to be a little
01:32:41.960 | bit dodgy, I guess, like it has to. I would not write a Yeah, I
01:32:46.680 | would not write a Bitcoin miner in it for sure. But I think for
01:32:50.680 | what is designed for, like little interactive elements,
01:32:53.400 | like where you embed the code, like it's designed to be
01:32:55.800 | embedded in HTML, like it's supposed to be and very readable.
01:33:00.160 | Like, that's one thing there's an essay, I think, what, there's
01:33:04.120 | an essay on the HTMX website about that about, I think it's
01:33:07.920 | right click view source extremism, I think is what I
01:33:10.960 | call it. Hold on, hold on. It's that last one. And so this is a
01:33:17.800 | kind of riffing on something like Cory doctora, who's a real
01:33:20.920 | good writer. Yeah, right about guys very passionate about the
01:33:23.680 | web. Yeah, yeah, 100%. And he talked about how, like the early
01:33:28.880 | web, you could always look, you could be like, one of the
01:33:31.200 | reasons why the web was so great is you could, if you saw
01:33:33.520 | something cool, you could right click and view the source and
01:33:35.520 | see what was going on. Yeah. And, and so that's one thing
01:33:39.640 | that I think HTMX and Hyperscript kind of have that.
01:33:43.040 | Yeah, like, I believe in that ethos, though, like, exactly.
01:33:46.520 | It's not open source. It's not open source. It's view source.
01:33:50.720 | It's no, no, exactly. Yeah. And in fact, you know, I really kind
01:33:55.080 | of leaned into that with, like, one of the things I created for
01:33:59.440 | fast HTML is like, I really love being able to like, even just
01:34:03.280 | view, you know, view HTMX or HTML or whatever source. And so
01:34:08.280 | one of the things I kind of show people in our very first video
01:34:10.720 | is this idea of like, copy outer HTML, paste it into HTX. And now
01:34:16.800 | you've got, you know, the fast tag tag ready to go. It's like,
01:34:20.240 | I really wanted people to be able to grab stuff that's out
01:34:23.840 | there. Yeah.
01:34:24.920 | Yeah, yeah, there's something that we've definitely lost in
01:34:27.800 | the web now that everything's like a huge massive, you know,
01:34:31.600 | either it's a bunch of like, you know, if you want to cry, like
01:34:34.480 | go and look at go to google.com and right click view source, and
01:34:38.880 | then go to the Wayback Machine. Oh, I know. And go to google.com
01:34:42.720 | and like 2002 and view the source of that. And it's just
01:34:46.080 | like, guys, what are we doing? You know, like, it's just crazy.
01:34:50.880 | Say that the current I don't find the current Google a better
01:34:54.400 | experience to use than that's not I mean, it's a little better
01:34:57.760 | in some ways. But you know, I do I do like the, the openness and
01:35:03.120 | that's one of the reason I'm on this kind of riff is just
01:35:06.480 | because Hyperscript is designed to be part of that. Like, yeah,
01:35:09.520 | you put the code in, you put the code directly in there. And you
01:35:13.480 | know, there's another one, I don't know if you've tried it
01:35:15.080 | at all. Which is a surreal JS, which is actually what what I
01:35:20.200 | am after you convinced me not to use Hyperscript. Yeah, I don't
01:35:24.680 | know. It's almost as weird, but not quite. But it's a similar
01:35:28.040 | idea. Yeah. So there's this like nice example here. Yeah, you
01:35:36.360 | know, where you can inspect these things. And yeah, they're
01:35:42.840 | just like, right there. And it's just, yeah, it's just a script
01:35:45.720 | tag right next to the thing. Yeah, yeah. And, you know, also
01:35:50.280 | this really beautiful CSS, like, not like this is 320 lines, you
01:35:56.520 | know, yeah. And then the CSS one is like 50 lines or 40 lines or
01:36:00.360 | something. But it's like, yeah, in many ways, it takes tailwinds
01:36:04.520 | us, you know, you just have like me, yeah, in your styles. And
01:36:08.680 | then it works really well with the fast HTML approach that we
01:36:15.240 | were trying to create Python components, you know, where it's
01:36:18.360 | just Python functions, and the Python functions are self
01:36:20.760 | contained. And so with something like HTMX, or with the surreal
01:36:24.600 | approaches, you know, everything is like, you don't need web
01:36:28.680 | components anymore, because right, the servers generating
01:36:32.600 | the components. So I'm really in that direction.
01:36:37.080 | Yeah, I think it's a good one. I it's, you know, and that's a
01:36:39.800 | quick, I mean, I guess, like, maybe a last question for you
01:36:42.040 | is, how's, how's fast HTML treating you? So you got a
01:36:45.320 | couple of negative content, it's always easy to focus on the
01:36:47.960 | negative stuff. But I've seen a tremendous amount of positive
01:36:50.360 | stuff, too. So yeah, it's been less than a week. Let's see,
01:36:58.280 | we've got 2.7 1000 stars on GitHub. So it's like people
01:37:02.760 | definitely gravitated to it. It was number one on Hacker News.
01:37:06.120 | Yeah. The reaction has been, yeah, it's interesting. Like,
01:37:13.480 | we get I get reactions to a few different things, right? So
01:37:17.160 | like, a lot of the people reacting to fast HTML aren't
01:37:19.640 | reacting to fast HTML at all. But actually, like, so for
01:37:24.440 | example, I use a different programming style guide, which
01:37:32.120 | I wrote fast AI style, instead of the one that most, pretty
01:37:35.160 | much everybody else uses called pep eight. Okay. And it's based
01:37:38.360 | on like, literally 60 years of study, you know, in other
01:37:41.880 | communities, like, it's not bad, right. But because people see
01:37:46.040 | my code looking different to what they used to, a lot of
01:37:47.880 | people just react like, this code is wrong, or it's bad, you
01:37:53.160 | know, although the other thing I've seen people react to is,
01:37:57.800 | like, wait, it's 91% Jupyter notebooks, it's actually worse
01:38:03.160 | than that, because the other 8% is auto generated. Like, yeah,
01:38:07.320 | it's like, it looks wrong. It's written wrong. It's written in
01:38:09.720 | the wrong system. So you know, I get a lot of that.
01:38:12.520 | I did. I get some of that too, with HTML. So yeah, doing it
01:38:19.640 | wrong.
01:38:20.280 | And then people are like, well, you know, you're never going to
01:38:24.680 | be able to create something that looks nice with like tailwind
01:38:27.800 | and stuff like this, you know, and I'm like, dude, this is like
01:38:30.600 | a fast HTML application right here. You know, it's, here's a
01:38:37.880 | great example. This thing here is like something that wrote,
01:38:40.760 | like a standalone thing. And then now that we've got it, you
01:38:44.600 | know, it's just like card 3d. There it is. And this is like,
01:38:49.480 | there's some things where I just, it's a bit like what
01:38:51.720 | you're seeing with HTMX, but to a lesser extent, where like,
01:38:55.960 | this one. So this is actually the current temperature. And
01:39:01.000 | it's like, well, how the hell are we getting the current
01:39:02.760 | temperature on the homepage of a really popular website? You
01:39:06.440 | know, and the cost of running this, you know, including the
01:39:14.440 | entire launch on Hacker News and all that is like, yeah, you
01:39:22.120 | know, it's gonna cost 20 bucks, right? Three bucks so far.
01:39:25.320 | Man, I need to look into a real way app.
01:39:27.320 | It's and the trick is that I just used Python, right? And
01:39:33.000 | this is this function actually has a cache on it. And, and
01:39:37.400 | then I realized like, well, actually what so the normal
01:39:39.400 | Python cache basically is just like a memoization cache. So
01:39:46.600 | it's like an LIU cache. So like, I wrote this tiny thing
01:39:51.320 | called flexi cache. You know, like everything I write Carson
01:39:57.240 | is just like tiny, right? So this is like one of the biggest
01:40:01.880 | functions I've ever written is like 30 lines of code. But with
01:40:06.200 | this cache, you can then say, you can basically define these
01:40:09.320 | things are called policies. So here's a policy cache, which is
01:40:13.560 | just like, Oh, let's check the time, you know, and you either
01:40:17.160 | return none if it's still in cache, or you return the new
01:40:19.880 | cache time, you know, you know, whatever state you need. So
01:40:23.240 | there's an end time policy. So like, we have, I basically
01:40:27.240 | replaced static site generators now, because I just returned
01:40:30.440 | file responses with an end time policy cache. So like, it
01:40:33.640 | literally gives you auto reload if the file changes, you know,
01:40:38.040 | that thing is showing if the weather has like a one minute
01:40:40.280 | time policy cache on it, and it's just a decorator on the
01:40:42.680 | function. And so now, you know, this, you know, just updates
01:40:46.920 | itself once a minute. So it's like using all of Python,
01:40:50.440 | really, it just feels great. So yeah, so to answer your
01:40:55.640 | question, you know, this kind of new generation of JavaScript
01:41:02.120 | only programmers, you know, there's quite a common reaction,
01:41:05.240 | which is like, you can't do all these things. It's like, you
01:41:09.800 | know, Instagram's written in Python, Dropbox is written in
01:41:12.840 | Python, like, it can definitely create whatever application you
01:41:16.440 | have in your head. Yeah. But then there's this fantastic
01:41:20.840 | group of like, very experienced coders, who have like, come in
01:41:27.880 | to our like, Discord channel and just been like, this is the
01:41:32.120 | thing, you know, so like, for example, Audrey and Daniel, I
01:41:34.760 | mentioned these fantastic authors, and you know, really
01:41:37.320 | great web developers. Within like, two days of checking it
01:41:41.240 | out. Not only had Audrey won a hackathon, they're like, we want
01:41:45.480 | to fly to Australia to spend two weeks working on this with
01:41:48.440 | you, please. Wow, they're going to be coming like next week or
01:41:51.240 | the week after, we're just going to hang out here in my
01:41:53.080 | backyard, man. Yeah. So like that kind of reaction of people
01:41:58.120 | who I really respect, who just go like, yeah, I want to focus
01:42:02.840 | on this as my work for a while. And they're reacting a lot to
01:42:10.200 | HTMX. Do you know what I mean? Like, I feel like what we're
01:42:12.440 | doing is we're providing this surface to allow people to
01:42:18.040 | create hypermedia applications. Right. You know, and it's just
01:42:24.200 | cobbling together like the idea of functional components that
01:42:27.400 | goes back a long time in like, OCaml, Haskell, Elm, of course,
01:42:32.280 | history, you know, then the, you know, the HTMX approach, you
01:42:37.000 | know, the, the ASGI approach of like simplifying HTML a whole
01:42:41.400 | lot, just kind of like cobbles together these things. And like
01:42:46.200 | the whole thing's like 100 lines of code, you know, and HTMX is
01:42:49.880 | pretty small as well, I think, right? The implementation.
01:42:52.600 | Yeah, it's well, I think it's, it's 4000 lines of code now, or
01:42:57.240 | maybe even 5000, because we added so many type annotations.
01:43:00.680 | I think if you looked at like actual lines of code, it's just
01:43:03.640 | I don't know, man. Okay, whatever. It found zero bugs, by
01:43:07.160 | the way, but it's gonna say I don't do type annotations in
01:43:10.360 | Python, because I've, yeah, we've got a pretty good test
01:43:14.280 | suite. So but it's all it's fine. It's all good. People want
01:43:17.560 | it. And now they've got it. So but, but it is, you know, yeah,
01:43:22.520 | I think if you boiled it down and sort of into normal code, I
01:43:27.240 | bet it's a couple 1000 lines of code. Yeah, you know, and I
01:43:30.520 | don't write the most efficient, like lines of code style code,
01:43:34.680 | I tend to write very plotting code were at this point. So but
01:43:40.600 | yeah, you know, I, you say it's only 800 lines of code, but
01:43:43.960 | obviously, it's 800 lines of code to do the right thing or a
01:43:47.720 | lot better than 100,000 lines of code that does the wrong thing.
01:43:51.320 | So that's one of the one good thing about getting kind of old
01:43:54.520 | is you start realizing what the right thing might be.
01:43:57.000 | Well, exactly. And you suddenly discover these people who have
01:43:59.400 | built, built the right thing, like when I came across surreal
01:44:02.440 | JS, and I was like, Oh, yeah, self contained components. It's
01:44:06.840 | almost like a kind of discovery again, if like, oh, there's
01:44:09.560 | these things that when you put them together, it creates
01:44:14.040 | something delightful, you know, and combine well, yeah. So I've
01:44:20.760 | created all these little apps now. So like this thing of the
01:44:23.880 | other day, I was like, I was on the plane. And so I started
01:44:27.240 | writing a blog post in Microsoft Word, you know, and I was like,
01:44:29.960 | okay, I want to convert this to Markdown. And I was like, okay,
01:44:34.520 | I can't find anything that does a great job of converting it to
01:44:36.600 | Markdown. I write a fast HTML app to convert it to Markdown
01:44:40.280 | that took me like, two hours, you know, chuck it up on the web.
01:44:44.680 | And I found like, this obscure little JavaScript library
01:44:48.280 | somebody had used. So I basically hooked up with HTMX,
01:44:51.320 | you know, I used HX spells, which lets you call JavaScript
01:44:55.880 | kind of before it passes it back to your handler. And so I was
01:45:00.120 | able to that way, get this JavaScript client side cleaned
01:45:02.680 | up thing. And then I used a Python Markdown converter, and
01:45:07.720 | then use that to update. And I it's kind of funny, though, the
01:45:11.480 | the way I actually had it set up is that you paste into this
01:45:14.440 | text box. The on paste event basically is the thing that
01:45:19.480 | causes the handler to happen. So it actually pastes the
01:45:23.480 | Markdown. So it's kind of this weird UI experience of like
01:45:27.960 | literally copy from Word and paste and the Markdown. So yeah,
01:45:34.200 | so I kind of create all these little things and they just feel
01:45:36.280 | good. And I think like, yeah, this is this is the right way to
01:45:40.360 | do this stuff.
01:45:41.160 | Well, it's really good that it's scratching your like the
01:45:45.720 | fact that you're using it. And it's not just you kind of
01:45:48.760 | inventing this tool for the world. You know, I think my
01:45:51.160 | team loves it too. Like my friend Jono, he wrote this
01:45:54.120 | thing called Moodle. It's so fun. And like, so he's somebody
01:45:58.040 | who spends all his weekends like tinkering with I don't know
01:46:01.640 | robots or art or whatever. He's a inveterate tinkerer. And
01:46:06.040 | nowadays, it's a good sign that he always wants to tinker with
01:46:09.640 | fast HTML. So he wrote this thing called Moodle, where you
01:46:13.880 | go to the site, and it gives you basically a Pictionary type
01:46:16.840 | word you have to draw. You start drawing it and then there
01:46:20.040 | are three different language, three different language models
01:46:22.680 | running in the background that are trying to guess what you're
01:46:24.520 | drawing. And as soon as one guesses correctly, you're done.
01:46:28.680 | And so there's like a leaderboard. It's all HTML based,
01:46:32.120 | you know, of like, who managed to reach word get it done the
01:46:34.600 | fastest, right? And again, it's combining like canvas and you
01:46:39.000 | know, all these things with like, oh, HTML can't do that.
01:46:45.160 | You know, it does the job. But exactly. And it's it's not that
01:46:48.920 | he like he makes isn't trying to do all that, right? It's there
01:46:52.040 | to work with canvas and with you know, JavaScript and whatever
01:46:55.320 | else it needs to work with. Yeah, we get our leaderboard and
01:46:58.040 | we get our like, you know, and we're using the WebSockets
01:47:01.400 | thing, which is nice. And I'm about to dig into the server
01:47:05.960 | side events extension. That looks nice as well. Yeah. Yeah,
01:47:09.480 | server side events. Those are, you know, two extensions Web
01:47:12.360 | Sockets and server side events. I like the server side events
01:47:14.920 | one. It's read only. So as long as you're just consuming stuff,
01:47:18.040 | it's good for language models that stream the results back to
01:47:21.960 | you. So you basically read it until it's finished. Totally.
01:47:24.520 | A lot of that, you know, being able to use that depends a lot
01:47:28.600 | on what your server side environment gives you too. So
01:47:31.480 | you know, if, if there's good support for it, using whatever
01:47:34.440 | your server side environment is, then you can, you can take
01:47:37.560 | advantage of them. Yeah, no, I mean, with ASGI, it's all like
01:47:40.040 | async Python. So everything works. Yeah, pretty cleanly. I
01:47:43.480 | mean, not as cleanly as the HyperScript example that you
01:47:47.320 | showed. Sure. The other thing I like about with these things
01:47:49.560 | like WebSockets or server side events or whatever is this idea
01:47:52.440 | of like, oh, you want to like stop the connection as like,
01:47:57.320 | well, you literally just return a new DOM element that doesn't
01:48:00.920 | have a WebSocket, you know, attribute in it anymore. Like
01:48:05.240 | it's like, yep. When you got a hammer, everything's a nail.
01:48:08.680 | Well, kind of in HTMX, everything is a nail. You know,
01:48:11.240 | it's like, everything's a div. No, no, no, I'm kidding.
01:48:14.280 | DOM elements. Everything's a DOM element. Not a div, but
01:48:18.520 | yeah. Yeah, I, you know, again, I feel like just what you said
01:48:23.320 | originally, like it's more, I discovered this than anything
01:48:25.720 | else. And it does, it works for a lot of stuff, you know? And
01:48:29.960 | if you're, you know, like, it sounds like what you got, you
01:48:31.800 | guys are approaching it the right way, which is, I'm not
01:48:34.120 | going to try and make HTMX do stuff it's not good at. I'm
01:48:38.360 | going to instead, I'm going to integrate with HTMX via events.
01:48:41.560 | And that's what I try to tell people. That's what in my mind
01:48:44.280 | makes someone a good HTMX developer is if they get that,
01:48:48.680 | okay, like start thinking in advance, and I've got these
01:48:51.480 | other tools that I want to integrate. Now, how do I
01:48:53.960 | integrate them cleanly? Hopefully they have a good
01:48:56.040 | event model, or maybe I have to impose one on top of it or
01:48:59.080 | something like that. So maybe I should think that's the right
01:49:01.400 | I should talk to you sometime about my coming up plans. I'm
01:49:04.760 | hoping to actually create a kind of like web programming from
01:49:08.280 | scratch course. And I've actually now created this whole
01:49:11.160 | thing where I like literally it's a notebook that starts
01:49:13.400 | with a socket handler and builds up HTTP and then builds
01:49:18.120 | up ASGI. And, you know, I'm really hoping that a lot of
01:49:23.480 | people will understand the pleasure of this style of web
01:49:27.640 | development. I also want to introduce people to things like
01:49:30.600 | pay five bucks a month to run your own VPS that you SSH into
01:49:34.200 | and you deploy things by r syncing to it. And, you know,
01:49:37.160 | yeah, it's a, it's a bit of a superpower, I think, to have
01:49:42.440 | those.
01:49:42.840 | It is. Absolutely. I'm teaching, I'm teaching a class at MSU this
01:49:47.240 | fall on hypermedia. And so I'll be teaching sort of similar
01:49:51.480 | things.
01:49:51.800 | Will you have a chance to record any of that?
01:49:54.360 | Or, you know, I've got to I've got to talk to the department.
01:49:57.560 | But maybe alternatively, you know, we can do something
01:50:02.840 | together where you could show some of your slides if you're
01:50:05.080 | allowed to and yeah, team up.
01:50:08.360 | Yeah, that sounds amazing. Yeah.
01:50:10.600 | Yeah, no, I'll I'll I need I just want to I need to right
01:50:14.840 | now it's summertime. So everyone's gone and no one
01:50:16.920 | responds. But, but I'll talk to him as soon as everyone they
01:50:21.080 | should be back in a couple weeks or so.
01:50:23.160 | Well, Carson, I really appreciate it must be getting a
01:50:25.320 | little late in the evening for you. So I feel like it's not too
01:50:30.360 | bad. I've learned a lot. And I feel like I've hopefully helped
01:50:33.640 | other people learn a lot. Yeah, is there anything else you
01:50:36.360 | wanted to say or ask or anything before we wrap up?
01:50:40.840 | No, I just, you know, congratulations on the launch.
01:50:43.080 | And I really appreciate, you know, your support.
01:50:45.160 | And like I said, you're unembarrassed by it, because I
01:50:48.520 | feel like all I'm doing is showing people what you already
01:50:50.920 | made. So I hope I don't get, you know, obviously, that's not
01:50:54.440 | true. But, you know, the I think the Python community has been a
01:50:59.720 | big source of, you know, HTML, people excited about HTML,
01:51:03.640 | because they can stay in Python. And so, you know, I'm just I'm
01:51:08.360 | excited to see what you guys are, what you guys are going to
01:51:10.680 | be able to do with this tool looks really, really neat.
01:51:13.160 | Thank you, sir. Have a great night.
01:51:15.000 | Yep. You as well.
01:51:16.760 | Bye bye.