DEV Community

Vaibhav Sharma
Vaibhav Sharma

Posted on

Unlocking the Magic of Single Page Applications with Django and HTMX

Django, renowned as the ‘web framework for perfectionists with deadlines,’ empowers developers to craft exceptional web applications. However, it may not inherently provide the immersive experience of a single page application (SPA). In this article, we’ll dive into how you can infuse the magic of single page applications into your Django projects using HTMX.

Reload Every Time

Imagine this: your web page reloads every time you click a link. Not exactly the seamless experience of a single page application, right? But what if I told you there’s a way to achieve that SPA-like feel without diving headfirst into the complexities of frameworks like React or Next? Enter HTMX, the secret sauce to elevate your Django projects.

HTMX empowers you with the ability to harness AJAX, CSS Transitions, WebSockets, and Server Sent Events directly within your HTML, using attributes. This means you can create cutting-edge user interfaces with the elegance and power of traditional hypertext.

As I delved into the HTMX documentation (yes, I’m a bit of a nerd!), two features immediately piqued my interest: hx-get , hx-swap and hx-target.

The hx-get attribute will cause an element to issue a GET to the specified URL and swap the HTML into the DOM using a swap strategy:
The hx-swap attribute allows you to specify how the response will be swapped in relative to the target of an AJAX request.
The hx-target attribute allows you to target a different element for swapping than the one issuing the AJAX request. The value of this attribute can be:

In Django, we often find ourselves crafting reusable components using Django Templates. These components are thoughtfully designed and reused (with the help of block tag).

Now, imagine a scenario where, instead of reloading an entire page, we seamlessly swap out the HTML content within a designated container. That’s the magic of creating a single-page application experience right within Django! The answer lies in leveraging the power of components you’ve already built. Yes, it’s entirely possible!

Wait, hold on a second! After a fleeting rush of serotonin, a nagging question began to occupy my thoughts: what if a user wants to navigate directly to a specific page? I mean, we can’t expect them to always follow the predetermined path, right? And here’s another conundrum — if we simply use hx-swap, it won't leave a trace in the user's browsing history. That would make for a rather disorienting user experience, wouldn't it?

I dove headfirst into the documentation, anticipating that this must be a common hurdle for many. Lo and behold, my intuition was spot on!

hx-replace-url. It does precisely what I need to ensure a seamless and user-friendly experience.

The hx-replace-url attribute, as its name implies, empowers you to replace the current URL within the browser's location history.

However, a crucial consideration dawned on me during my deep dive into the documentation (HTMX Docs FTW!): while this attribute works like a charm for URL manipulation, it comes with a caveat. By using it, we effectively hide the entire location history from the user's view."

[https://htmx.org/attributes/hx-replace-url/](https://htmx.org/attributes/hx-replace-url/)

The hx-push-url attribute allows you to push a URL into the browser location history. This creates a new history entry, allowing navigation with the browser’s back and forward buttons. htmx snapshots the current DOM and saves it into its history cache, and restores from this cache on navigation.

Now that we’ve untangled the mysteries of HTMX and URL manipulation, it’s time to roll up our sleeves and start building! For this exciting journey, we’ll be harnessing the power of Django, spicing things up with the awesome Sneat theme, and, of course, weaving the magic of HTMX throughout.

Curious to see what we’re cooking up? You can catch a glimpse of this project in action over at my GitHub repository: https://github.com/vaaibhavsharma/djangohtmx

Project Structure

At the core of our project stands the main.html file, a pivotal element encompassing all our essential links, CSS styles, JavaScript code, and the requisite standard boilerplate. It serves as the foundation upon which our web application is built and I divided everything else in components,

   <html>
      <head>
        <!--ALL LINKS CSS OTHERS THINGS -->
      </head>

    <body>
        <sidebar>
          <!-- NAV BAR CONTENTS -->
        </sidebar>
        <div class="content-wrapper">
          <!-- Content -->
          <div class="container-xxl flex-grow-1 container-p-y" id="content-div">
              {% block content %} {% endblock content %}
          </div>
        </div>
    </body>
    </html>
Enter fullscreen mode Exit fullscreen mode

Ideally components will look like this

    {% extends "singlepage/main.html" %}

    {% block content %}
        // ALL HTML RELATED TO THIS PAGE (DASHBOARD IN MY CASE)
    {% endblock content %}
Enter fullscreen mode Exit fullscreen mode

(IMPORTANT) However, it’s crucial to note a critical nuance in this process. I cannot merely include this content within the main.html file as-is. The reason being, when I trigger an hx-get action, my server is expected to respond with only the specific segment of the page that needs to be swapped. If I were to provide a standard, complete page layout, it would result in the server rendering the entire page. The outcome of such an approach would be something akin to a jumbled mishmash that I can only describe as 'IDK WHAT IT IS'.

     <li class="menu-item">
          <a hx-get="{% url 'home' %}" hx-target="#content-div" class="menu-link">
            <i class="menu-icon tf-icons bx bx-home-circle"></i>
               <div data-i18n="Analytics">Dashboard</div>
          </a>
     </li>
Enter fullscreen mode Exit fullscreen mode

Strange Things Happening (!)

PARTIAL LOADING

In essence, Partial Loading entails finding a method to deliver the complete page when requested in the standard manner, while, in the context of HTMX Requests, responding with solely the HTML corresponding to the specific section.

To achieve this, we employ the versatile django-htmx library. With this we gain the ability to effortlessly switch between full-page rendering and targeted HTML template responses based on the nature of the request.

Diving deeper into the mechanics of django-htmx, It seamlessly integrates htmx functionality into our Django project’s request-handling process.
When a user interacts with our web application, django-htmx dynamically attaches HTMX behaviors to the corresponding HTTP requests. These behaviors enable us to perform partial page updates without the need to reload the entire webpage.

Here’s where the magic happens: based on the specific request and its associated HTMX action, django-htmx efficiently manages the server’s response. In cases where a standard, full-page load is required, it ensures the delivery of the complete HTML page as expected. However, when an HTMX request is made, django-htmx is cleverly configured to respond with only the HTML template relevant to the particular component or section being updated.

This intelligent orchestration of responses empowers us to create a fluid user experience that combines the efficiency of single-page applications with the robustness of Django. The result is a dynamic, responsive web application that feels both intuitive and performant.

After following very simple installation process, we’re ready to test it

However, managing two separate HTML files for the same component can potentially compromise code maintainability. To streamline this process, we’ve devised a straightforward solution: integrating the partial template into the full template.

In practice, this translates to having our partial code residing in one file, say ‘dashboard.html,’ and the complete content within another, aptly named ‘dashboard_full.html.

So, after setting hx-push-url=“true” , HTML Code looked like this

And this gives us full one page feel

Take a moment to observe how the URLs dynamically change as we navigate through our application. However, there’s a subtle yet c*rucial aspect that demands our attention.* When we employ the back or front buttons in our browser, an unexpected issue arises. This dilemma stems from the fact that the browser’s history management struggles to accurately load the correct elements.

To address this challenge, we are faced with two potential paths. The first involves implementing JavaScript logic to reload the entire page with each navigation action — a solution that inadvertently contradicts the very essence of our single-page application goals.

Fortunately, **HTMX have a solution: the hx-history-eltattribute. **This attribute empowers us to designate a specific element responsible for capturing and restoring the page’s state during navigation. By default, it targets the ‘body’ tag, which suffices for most scenarios. However, for our precise requirements, we’ve opted to narrow it down to a child element — in our case, the ‘main-container’ div. This strategic choice ensures that the element remains consistently visible within our application, enabling HTMX to seamlessly restore the history navigation state.

this does the trick and Gives us Single page application feel!!

GOAL ACCOMPLISHED!

In Conclusion, I really learned a lot While exploring HTMX, Thank you for reading this blog! I’m always up for Suggestions.

Article Originally Published on Medium

Top comments (1)

Collapse
 
matthewekeller profile image
matthewekeller

This would be much easier with WebRocketX in front of Django. You are cobbling together a lot of HTMX functionality to create a SPA which means you are coding your own SPA in detail. Instead you can simply leverage a proven solution and focus on just returning your view from your server instead, and let the framework manage the views for you.