Modern web apps with (almost) no JS: Enhancing UX with HTMX in Django

This video features Krystof Beuermann at Django Day Copenhagen 2024 in Copenhagen, Denmark.

Modern web apps with (almost) no JS: Enhancing UX with HTMX in Django
0:26:15
Published October 13, 2024
1,055 views

Django Day Copenhagen 2024 talk descriptions: https://2024.djangoday.dk/

Summary

HTMX lets Django applications add interactions such as infinite scrolling, live search, partial updates, and likes without building a separate JavaScript front end. The speaker shows how HTMX attributes send requests and replace targeted HTML, allowing Django views and templates to return server-rendered partials instead of JSON, while preserving simple code, progressive enhancement, and existing Django patterns. He recommends it for focused enhancements but cautions that highly dynamic interfaces with many dependent updates can become difficult to manage.

Key takeaways

  • HTMX adds behavior to ordinary HTML through attributes such as hx-get, hx-post, hx-trigger, hx-target, and hx-swap.
  • Django views can return HTML partials directly, avoiding the extra JSON, state management, and build tooling often required by React-style front ends.
  • Infinite scrolling can reuse Django pagination by loading the next page when the last visible element intersects the viewport.
  • HTMX updates only the relevant element, so actions such as liking a post do not reload the page or lose the user’s scroll position.
  • The library works well for progressive enhancement and small, focused interactions, but complex highly dynamic pages may become difficult to structure.
  • WebSockets and server-sent events are also possible through HTMX extensions, including an example chatbot built without custom JavaScript.

Summarised automatically from the transcript.

Transcript

4,338 words · auto-generated Show

Automatically transcribed, so expect mistakes in names and technical terms.

0:00

Speaker 1: We're ready on stage here with us. Um not that one, but this one. Christoph, thank you so much for coming. Very excited about your talk. Uh please give Christoph a a big hand

0:16

Speaker 2: Okay, yeah, thank you. My name is Christoph and I'm going to talk about HTMX uh today. Andrea already introduced the great tool uh to us and I'm going to bit give it a little bit of flesh. And yeah, I brought my sponsor here And uh when I woke up this morning I looked at the slide and then I thought to myself, okay, you cannot show Trump. I removed him. And then one hour ago I found out, okay, this uh audience they get the humor, I'll just put him back in So yeah. Maybe this would make him more popular if this was his theme. So maybe make web development great again. And this is also my talk. Okay. I brought some examples today of what a typical user or a typical client is probably expecting of a web application.

1:03

Speaker 2: Like this is the first example that I show here. I hope that you can see this is the video. The numbers here are changing all the time. This is a screenshot from a crypto page which lists the prices of Bitcoin and all the other um crypto uh things. And this page does not reload, right? You see, okay, because this is only a part of a page, it all the numbers are all always changing, and you can ask yourself, okay, how did they do this? They must leverage some kind of JavaScript probably to achieve this because in a regular Django way you would have to do like a full reload and show the prices but then again okay okay all the rest of the page would also reload But yeah, that's a theme or a thing that you see on many web pages.

1:51

Speaker 2: Another topic that I brought here today is called active search. And I think a lot of you know this. This is a Google search where you type stuff in and it directly shows you the results. So you do not have to hit the search button and the page reloads. So yeah. And so this is so what are people searching here? Django is Django is gay, I think I've seen. I don't know why people maybe the music musician. Yeah, but this is a great uh thing to show um results in a very fast way. And again here, how would you do this with just HTML and Django? Would be pretty hard and you wouldn't need to use a lot of JavaScript.

2:38

Speaker 2: Or look at this example, Infinite Scroll. I think in times of Instagram, Twitter, you name it, all the social networks. And yeah, I mean all all already all of the pages, they have this scroll when so when you reach the bottom of the page. In the background, it directly reloads the content. And as long as there's enough content to be shown, you'll never reach the bottom of the page. But you don't have to click, okay, please please show me page two or page three, because I would say this is an old pattern, but this is a pattern that Django supports. And so you will always have the question, okay, how can I solve this with Django and do I need to learn JavaScript to have like an infinite scroll

3:28

Speaker 2: So this is the way I showed you how how you would do this with Django. We have like the pagination at the bottom of the page. You click on the page, you see okay, there are 97 pages around here, and then you click on page two, page three. Okay, you can do it like this, but I think nobody would say this is modern or um this is the cool way to do it. Or even some users say okay, please do not do this, or customers tell you please do it in the infinite scroll way. But still this is the old Web 1. 0 way. And of course, pick a random front-end developer and ask them how would you solve this infinite scroll problem? And then I'm pretty sure that they would name some of these frameworks, libraries, and whatever you see around here.

4:14

Speaker 2: It's like React, okay, you can use Angular Next. js and then okay, you have to test it with storybook. Yeah, but please use TypeScript, of course, because it needs to be type safe. Yeah, that this is totally fine and I don't say that this is a bad approach, but maybe for us Django developers, it's also stuff that we need to put into our heads and something that we need to learn. In addition to the stuff that we already know. So okay, maybe we know Python very very well, HTML very well, but okay, so we need to learn TypeScript again. learn React which has its own paradigm, then you need to learn state management in the front end, which can get pretty complicated. And not yeah, so my talk is make web development great again.

5:00

Speaker 2: So maybe is there some kind of way to make this simpler. And yeah, of course you can do uh use React and yeah I this I did this on purpose so you cannot read this but this this is the actual React component to solve the infinite scroll problem And you can see, okay, this works. You don't have the pagination there. It refreshes in the background. But I'm sure okay, this is a lot of code. Really, really, really lots of code. And can you can't we do this any simpler? And the answer is yes. Why not use HTMX for this? And this is the first example that I brought. So

5:45

Speaker 2: look at this code, and you have the product list here, so it's pretty easy uh to read for a Django developer. And the part uh on the bottom of the page, I don't know, maybe six lines of code This is the code that you need to put in there to achieve the same result and have the infinite scroll. I'll explain this later, but this is the the first example that I wanted to show you that you can use much lesser code for the same result. And I'm think uh I think that we can all agree that this is great and that this is better than having like a huge application around. which which we also need to test. So okay, maybe use HTMX to solve the pr

6:31

Speaker 2: this problem. Yes, I my idea was okay how do I teach you guys HTMX? I would say, and this is what also the author of the library says, HTMX adds superpowers to your existing HTML elements. So this is like the the minimum viable example I can show you so you understand how HTMX works. Of course you have since it's a JavaScript framework, you have to include it in your script check. And to use it, it has like these special hx attributes, like hxget, which tells the browser please make a GET request. H at target here, please take the response from the get result uh request

7:16

Speaker 2: and put this into the result div. And this is triggered only on click, so when I click the button, or also every second. So if we translate this to plain English, we would say, okay, please make a GET request to the endpoint. When clicked and every second and update the results um element with a response. So yeah, this is it. I could stop right now because this is like the main message of HTMX is just um so you understand What the difference here is to maybe the difference from the um reacts approach that I showed you, because right here we would require the endpoint. to return HTML and not JSON. This is like the the main difference. And I think this also feels a little bit more

8:05

Speaker 2: How we would like to approach this because okay, why do we need JSON to display HTML if we don't only have a web app? Of of course if we maybe have a mobile app and need to display it there too. Yeah, but I don't know how many products have you built where you have have a mobile app Which is not uh web the web app and uh um the traditional web application. I haven't built those so far because I don't know cli if they if Clients hear the price of a really uh native uh web mobile app, they're gone. And so this is like the most simple um example that I can show you Yes, the typical single-page application approach would be like this.

8:52

Speaker 2: You have your Java, uh your Django backend, this validates the logic, transforms it into JSON, then you have the React front end, which Sometimes validates it again, returns the JSON into HTML and renders it into the browser. So far so good, but also so complex I would say So now we could how does HMX make this simpler? It just turns this into this. Which I would say is easier to understand. You just have your Django, your backend, and this sends HTML to the browser like we always do. Why not in this way? So yeah, I think you're getting the idea why I think HTMX is so great because it's just it uses the approach that we do all the time to do some cool stuff.

9:42

Speaker 2: And this is another example that I showed you. Maybe you have some kind of social network around and you have a post and you just want to increase the like count of one post. So yeah, you cannot see this. So this is like the post around here. So if you click the like button, we want to increase the like count And the traditional approach would be to, okay, we use a form and a button, and the like count is inside the button, and then we have our Django view, like post. It gets the post object, increases the like count, saves it, and then redirects to the detail page so the whole page flashes and shows the updated post again. Yeah, but this approach has some downsides as you can imagine because I don't know maybe you scroll

10:30

Speaker 2: down somewhere and like the post and the page reloads and suddenly you're at the beginning of the top uh page again because the brow browser does not uh scroll for you you have to scroll again so maybe okay this is not a very good approach to solve this problem How would we do this with HTMX? Again, you have the button here, you do not need a form, you just take the button and let it say, okay, please post to this URL. When when you clicked on yourself, you could even omit the trigger click because this is for buttons this is the default. The target for the response will be this, so yourself. So please swap out everything from the response that you were sent.

11:16

Speaker 2: How would this look on the Django side? Again, okay, we'll take the post object. Increase the lag count, save the object. Yeah, but the difference between this example and the example that I showed you before, we do not do the redirect here, we'll just return the button. We could even do it differently and just uh return the inside of the button because this is the only thing that is really changing and send this to the browser again. And since the browser uses HTMX here, it will just switch out the button to the updated button, and the page and the scroll position will all stay the same So yeah, I think this is pretty great and pretty easy to achieve. So yeah, I showed the example of active

12:03

Speaker 2: search before. And this is a way how to do active search with HTMX. Also, pretty simple because this is all the front-end part that you need to have an active search on your component. You do not need JavaScript at all. You have just the HXget here. So you have a Django view, which is responsible for search posts. The trigger is when the user types. You have the key up event, so they type and it waits for 500 milliseconds, so maybe they type even more. And when the value has finally changed It takes what you have typed and sends it to the get URL and takes the response from the server. I'll show you the view in a second, and puts the results into my

12:51

Speaker 2: search results diff. Which is underneath here. Yeah, so this is uh explains what it does. Again, I think pr pretty easy to understand, even if you haven't seen uh HTMX before. I'm pretty sure that all of you can initially say what this does. So it's really, really easy to understand. And yeah, for me, I think uh this is the reason why it's uh so fun uh to use. Yes, so this is the example here. This is the Django view that we have. And yeah, again, this is really not a lot of code. You uh get the the queue, which is what the user typed, make the search with the Django RM, and then you just use the render to

13:37

Speaker 2: string method from Django. And this is the reason why HTMX and Django are such a great fit, because it's HTMX works with all the Django stuff that is already there, like the render render to string button, um render to string function, and you just return the response. that you want to show here. And this would be the search results HTML partial. I think Andrea already introduced you to the concept of partials. So you do not return the whole page, you just return the part of the page that you want to reload. And this is like the main thing that HTMX does So again here, this is how this works in reality. You type, it waits 500 milliseconds, takes your input, and brings it to the front end.

14:23

Speaker 2: Or Andrea already uh introduced the Django HTMX library, you could even, this is active search is even better. Because in the example before you would need two Django views. You would need to have the viewer that displays the form and the viewer that returns the results. You could even just do one view where you decide, okay, is this a request that has been done by HTMX? Then we'll just return the search results. Or did the user just load the page, then will return the full page? So this is really, really nice to um have a small amount of code for a lot of functionality. Yeah, and I'll sum up the reasons why I really like HTMX and yeah, why I think it's a great fit for um

15:09

Speaker 2: Django. It's simple and lightweight. If you introduce um use uh the CDN version of HTMX, I think the size is about 19 kilobytes, and that's all you you need to uh include in your page. I don't know if you have my if you have tried out Next. js and make a production build of that to and try to fit this into 19 kilobytes. I I'm pretty sure that you will not get very far with this You don't need a build process at all because you just include HTMX in your script tag and you're done. Of course you can introduce uh whether you or you can use it with uh JavaScript like Andreas said, but I think if you have seen the examples I showed you before, there was no JavaScript at all.

15:56

Speaker 2: It was all included in the tags. So we have minimum JavaScript. And yeah, as I showed you, uh it really really integrates nicely with Django. So you can use this the um Django functionality. You could even use the pagination that Django supports, and but not display the um the search uh the the foota with the single pages and just just use uh the Django pagination but have it nicely as uh in finite scroll And this all keeps it very pathonic, I would say. And yeah. And for me, and this is was this is like one of the things that I want that you get This is really making fun and uh I think it's easy to learn, it's easy to read, and it's also easy to introduce and use in your existing projects.

16:47

Speaker 2: So you can use a look at your projects and say, okay, I would like to have an infinite scroll here. I already have a list view. Maybe I can take out the pagination stuff. And just switch for this list view and use HTMX here and keeps everything else as it is. So this is really nice. Yeah, and since this is all um server-side rendered, it's also CO-friendly. And yeah, because of all everything that I said, I think this is really really easy to yeah for for you to boost your productivity because you don't write lots of code, but you get lots of results. Yes, and to say um further reading, there's a very very book uh great book which is called Hyper Media Systems by Carson Gross.

17:32

Speaker 2: I think Andrea already uh mentioned him, he's the creator of HTMX. And this book is free to download. You can also buy it if you want a printed version. But this is it's very, very nice read because he also explains the um the the principles that are behind HTMX like uh Carson Gross wanted to take um HTML and add all the stuff that he thinks is missing. Like why do you have in uh HTML only the form that can submit data and the A tag. Why cannot uh button do a post? This was like one of the questions he had and HTML doesn't support this out of the box. And he also thinks that this is probably not coming.

18:18

Speaker 2: So this was a his idea, okay, how do I get this here? I make this myself and this is the result is the HTMX library. And on the HMX page here has lots of great examples of the things that I couldn't show you today just because of time. Also stuff like maybe you that if you want to edit an object and just uh do not you want to use the update view that Django gives, maybe you want to do it in a modern way and open a model so that doesn't page uh doesn't reload and just edit the thing that you want to edit and update the result. You can use HMX for this as well. We can talk about uh this uh if you want uh after the talk Yes, and this brings me to the end. I hope that you got the idea why I love this library so much and why I use it in almost all of our products.

19:05

Speaker 2: And say thank you very much.

19:13

Speaker 1: Thank you. We have a lot of talk uh time for uh questions, so Let's take the first question there. And there's another question.

19:24

Speaker 3: Hello, and thank you for a nice talk. Um can you elaborate a bit over where you would feel the limits of HTML?

19:31

Speaker 2: Yeah, I was uh thinking about this and um if Andrea didn't do his talk, I would say I would not build Google Maps with HTMX. Because but he told yeah, he taught us the lesson, okay, maybe there's even a solution for this. Yeah, but I wouldn't use HTMX if you need a lot of dynamic stuff uh on the page. Recently we use it in one um in one product where we have a detail view and this date detail view There are a lot of dependent fields. So if you select one drop down the content, the next reloads. And if you select content there, the next part of the page reloads. And I did this all with HTMX But yeah, it turned into a big ball of mud, maybe because I didn't do it well, but I felt okay maybe for this, for making really, really rich

20:19

Speaker 2: dynamic applications, it's not the great tool. But yeah, like for small purposes like Infinite Scroll or update one entity, I think it's a perfect tool.

20:34

Speaker 4: Thank you for your talk um and great introduction to HTMX. This is a little specific uh question, the infinite scroll thing. Um It looked like that uh you know we do pagination because we don't want to load everything at once.

20:52

Speaker 2: Yeah.

20:53

Speaker 4: But it looked like in the example you had that You did load everything at once, am I right?

20:59

Speaker 2: It was a little bit simplified, yes. And then there's a parameter called intersect, which tells the browser, okay, when the user when is when this part is visible, which is typically like the last element. Then please load the next page in the background and put this underneath the page so the user can scroll again. Yes. But a good eye because I missed this part and wanted to keep it as simple as possible. Yeah, but it will all stay the same. So you just load the first page and when it's revealed, load the next page, and when it's revealed, load the next page until there are no pages left

21:42

Speaker 1: Next question.

21:44

Speaker 5: Hey, thanks for your talk. Uh did you try using HTMX with WebSockets in Django?

21:51

Speaker 2: Yes. I use HMX with WebSockets and also with service and events. For one client, we build a chatbot to the OpenAI API. And my first idea was okay of course I can build this with React, no, no problem. But I had the I wanted to make myself a task okay maybe I can build this with no javascript and it was possible. There's a plugin uh or an extension called HXWS for WebSockets and they also support um service and events out of the box with these plugins. So it's it's yeah, it's usable and it works.

22:31

Speaker 1: If you want to uh Build something that's friendly for browsers or bots that don't have JavaScript. Is it easy to uh tailor these solutions so they also work if you say remove the HTML?

22:46

Speaker 2: Yeah, absolutely. I think the the it's called progressive enhancement where you have like the basic layout of the page and you could even Because if the browser doesn't recognize the HX tags, it would just do nothing. So you can absolutely do this and then show the pagination. Okay, but then you have would have to use a little bit of Java script to see if if this browser uh supports this or that.

23:12

Speaker 1: Yeah.

23:13

Speaker 2: But the idea is, and this is well like one of the core principles, um, that you can enrich your application with this. So it really works or you can make it work without, which is not possible if you have you use like React or something. So if you use React and disable JavaScript, if you don't do anything, you just have a blank page.

23:34

Speaker 1: The question in the front.

23:39

Speaker 6: Um something that I've been thinking about a little is You in your exam you used uh render to string. Have you had considerations whether to just use render and have like a small Yeah, absolutely. What are your considerations between having the HTML and Python code or kind of putting it in in a a small template.

24:04

Speaker 2: Uh absolutely this was just for demonstration purse uh purposes. Please do not do this in your production views. Yeah, but my uh take would be to avoid writing HTML directly into a Python file. You can also uh I think I showed it in one example where you can use um the render function and then pass the partial but you can also use like a Django generic detail view and have the get template names and inside the get template names you decide is this a HTMX call Okay, then I return this template and if it's not uh uh HMX call, I just return the regular template. Yes.

24:49

Speaker 1: Any other questions? You mentioned earlier the users' expectations. Is that a good way to start the process of deciding whether to use HTMX or not.

25:04

Speaker 2: I think it depends always the answer. Yeah I think we talked about that Django is turning twenty next year and I think some of the concepts that uh Django supports, they they feel a little bit old. So yeah, of course you have to d decide this on every uh thing that you um that you do do I want it this way or do I want it that that way? Do I need to build like a simple prototype? Of course I can just use um the existing pagination and this totally works. But maybe I want to polish my product or um maybe a customer even demands it. I don't know if customers really demand this. I don't know. But you know the bar is getting higher and higher every year and I think you at least need to have some way to handle this. Of course you have to decide

25:50

Speaker 2: do I want this or not, but I think it's always good to have the possibility to uh to have a solution for this that does not use javascript.

26:03

Speaker 1: Ah well in that case uh let's give Christoph a big round of applause. Thank you so so much. Great talk.

Questions this talk answers

How does HTMX simplify Django web apps compared with React?

HTMX adds behavior through HTML attributes such as `hx-get` and `hx-target`, so Django can return HTML partials directly instead of sending JSON for a JavaScript front end to render. This keeps the existing server-rendered Django approach while enabling dynamic interactions with much less code.

Discussed at 6:31

How can I update a like count without reloading or losing the scroll position?

Have the button post directly to a Django endpoint and target itself with HTMX. The view increments and saves the count, then returns the updated button or its contents, allowing HTMX to replace only that part of the page.

Discussed at 10:30

How do I build active search with HTMX and Django?

Add an `hx-get` to the search field, trigger it on keyup with a short delay, and place the returned results in a results element. The Django view reads the query, searches with the ORM, and returns only the results partial.

Discussed at 12:03

What are the main benefits of using HTMX with Django?

HTMX is small, needs no build process, can provide dynamic behavior with minimal or no custom JavaScript, and integrates naturally with Django views, templates, pagination, and server-side rendering. The speaker also highlights that it is easy to learn, readable, SEO-friendly, and useful for improving existing projects incrementally.

Discussed at 15:09

When should you not use HTMX?

HTMX is a poor fit for very rich, highly dynamic applications with many interdependent updates, where the interactions can become a difficult-to-maintain tangle. The speaker considers it ideal for focused tasks such as infinite scroll or updating one entity, but not necessarily for something like Google Maps.

Discussed at 19:31

How do you implement infinite scroll in Django with HTMX?

Use HTMX to request the next paginated result and insert it below the existing list when the last element becomes visible, using the `intersect` trigger. The page loads one page at a time rather than loading all records at once.

Discussed at 20:59

Can HTMX work with WebSockets in Django?

Yes. The speaker used HTMX with WebSockets and server-sent events, including a chatbot, through the HXWS extension and related plugins.

Discussed at 21:51

Can an HTMX application work when JavaScript is disabled?

Yes, through progressive enhancement: the basic page can still work because browsers that do not understand HTMX attributes ignore them, while the application falls back to normal server-rendered behavior such as pagination. This may require a small amount of JavaScript to detect support, but unlike a typical React app it need not become a blank page.

Discussed at 22:46

Should I put returned HTML directly in a Django view, or use templates with HTMX?

The inline HTML shown in the talk was only for demonstration and should not be used in production. In production, return a Django template or partial—possibly selecting an HTMX-specific template in `get_template_names()`—rather than writing HTML directly in Python.

Discussed at 24:04

Note: We understand that names change, people change, and bodies change. We respect each individual's journey and privacy. If you have any concerns about a video or need us to remove content, please don't hesitate to contact us. We will handle your request with care and promptly address any issues.

More videos from Django Day Copenhagen