Logo

How to handle 404 errors with htmx in Django

Enhance user experience by gracefully handling 404 errors with htmx in Django

Published: 12 Feb, 2025


In a traditional web app, users are usually redirected to a 404 page if they try to access a resource that doesn’t exist.

When using htmx, resources are fetched using AJAX and then swapped into the DOM. If a resource doesn’t exist, htmx won’t perform any swapping, leaving the user in the dark.

Here’s an example:

404 errors show up in console only

The user clicks on the get post button, and a post is swapped in by htmx. When the user clicks on get post again, a 404 error is returned, but the user can’t tell what’s happening.

In this post, I’ll show you how to solve this problem by displaying an error message when 404 errors are raised from Django views.

See this git repository for a complete example.

The not found middleware

Django views that retrieve resources will typically raise the Http404 exception if a resource doesn’t exist. Functions like get_object_or_404 raise this exception under the hood.

For example:

from django.http import Http404

def invalid_post(request):
    raise Http404("Post not found")

This is fine for traditional views that aren’t accessed by htmx because Django will redirect users to a dedicated 404 page. When using htmx, we need a way to tell the user that a 404 error has been encountered, without having to redirect them to the 404 error page.

We’ll use middleware to solve this problem:

from django.http import HttpResponse
from django_htmx.http import trigger_client_event

def htmx_not_found_middleware(get_response):
    def middleware(request):
        response = get_response(request)

        if request.htmx and response.status_code == 404:
            response = HttpResponse("", status=404)
            return trigger_client_event(response, "htmx-not-found")
        return response

    return middleware

Install django-htmx because it provides tools that make it easier to communicate with htmx.

Add the middleware to your list:

MIDDLEWARE = [
    ...
    "django_htmx.middleware.HtmxMiddleware",
    "my_package.middleware.htmx_not_found_middleware",
]

Ensure that HtmxMiddleware is above the one you created.

Our middleware will check if the request was made by htmx, and if the response’s status is 404. This will be set if any view raises Http404. We will instruct htmx to trigger an event called htmx-not-found on the client.

Handling the error on the client

I like to show an alert to notify the user about the error on the front-end. Let’s use SweetAlert2.

The listener is dead simple:

document.addEventListener("htmx-not-found", () => {
  Swal.fire({
    icon: "error",
    title: "Oops...",
    text: "Post not found!",
  });
});

Here’s the result:

htmx not found alert

Conclusion

Triggering client-side events is a powerful htmx pattern that allows you to easily communicate with the browser from your backend.

I’ve previously written about how to use it to show modals. In this post, you saw how easy it is to handle 404 errors using the same method. You can do the same thing for any other type of errors (503, 403, 400, etc) where redirection is the usual pattern.

Feel free to email me if you have any questions about this post or anything else related to htmx.

I'm currently available for freelance work. If you know someone who would benefit from my expertise, please direct them to my work page, or email me their contact details.


Email me if you have any questions about this post.

Subscribe to the RSS feed to keep updated.