layers Introducing Unfold components - Pre-made HTML blocks in Django admin for custom dashboards arrow_forward

Creating modal windows with Alpine.js and HTMX

Creating a modal window is a pretty common task when building a new website but sometimes it is not obvious how to do it by just using HTMX and Alpine.js. Both libraries are going to be complementary in building a proper modal window experience.

  • calendar_month 4.1.2024
  • pace 10 minutes

In the example below, we are going to build a modal window that will be opened by clicking on a link. The content will be loaded into a modal window. To dismiss the window user has to click outside of the modal window or hit the escape button. One additional feature that we will add is the possibility to share a link after opening a modal window.

Responsibilities of HTMX and Alpine.js libraries

  • HTMX will load content from an external URL and it will change the URL link
  • Alpine.js will take care of opening/closing the modal window and it will reset the URL

Base template for the link and modal window

Let's start with the basic skeleton of our modal window experience. On the body element, we will specify several attributes for Alpine.js. x-data attribute is responsible for declaring a new variable in Alpine.js called openModal which holds a flag if the modal window is open or not. x-bind:class is chanding CSS classes on body element based on openModal variable. In the example below it will add overflow-hidden CSS class when the modal window is open.

In the post example, Tailwind classes are used to style the components. The overflow-hidden class on body element hides the main content scrollbar so it will be not possible to scroll the main content area. Later we will add a scrollbar on the modal window which allows to scroll modal's content.

<body x-data="{openModal: false}"
      x-bind:class="openModal && 'overflow-hidden'">

    <!-- Link template here-->

    <!-- Modal template here -->

    <!-- Don't forget to load libraries -->
    <script defer src="/js/htmx.js"></script>
    <script defer src="/js/alpine.js"></script>
</body>
</html>

Modal window

The most important part of the implementation is the modal window below. It consists of three important parts. The main container has x-show attribute for controlling when the modal window is open or closed. The x-on action will close the modal window once the escape button is hit and it will change the URL.

The background overlay is a straightforward HTML element. It adds a layer below a modal window covering the main content. The example below has a dark background with some opacity so the content below is barely visible.

The main component in the example is the modal window itself. It has a fixed position and overflow-auto CSS class which is for adding a scrollbar when the modal's content is larger than the window's height. There is x-on:click.outside attribute which will close the modal. The div element with id modal-content is the wrapper where the content is going to be loaded.

<div x-show="openModal"
     x-on:keydown.escape.window="openModal = false; history.pushState({}, '', '/')">

    <!-- Background overlay -->
    <div class="bg-slate-900/80 bottom-0 fixed left-0 right-0 top-0 z-20"></div>

    <!-- Modal window styling-->
    <div class="fixed bottom-0 p-6 left-0 overflow-auto right-0 top-0 z-30 lg:py-24">
        <div class="container max-w-7xl mx-auto relative shadow-lg z-90"
             x-on:click.outside="openModal = false; history.pushState({}, '', '/')">
            <!-- Main content from HTMX will be inserted here-->
            <div id="modal-content" class="bg-white p-6 rounded-lg lg:p-12"></div>
        </div>
    </div>
</div>

Link with Alpine.js and HTMX triggers

Let's create a basic link pointing at the URL with the desired content. Below you can find an example HTML which can be copied and pasted inside the codebase. Of course, links have to be changed. The code below will create a basic hyperlink. When the user clicks on it, the target URL with queried, and HTMX will find post-content element which will be put into modal-content. After that, Alpine.js will be informed that a modal window can be opened.

<a href="/some-content"
   hx-get="/some-content"
   hx-select="#post-content"
   hx-target="#modal-content"
   hx-push-url="true"
   x-on:htmx:after-on-load="openModal = true">
    Link pointing at the content
</a>

It is important to not forget to create under /some-content URL a div element with id post-content. This element will be used by HTMX to load just a part of the response into the modal window instead of the whole response.

Detailed description of Alpine.js and HTMX attributes

  • href contains a link pointing at the content that we want to fetch
  • hx-get tells HTMX to trigger GET query
  • hx-select will choose an HTML element from the response
  • hx-target where the content is going to be appended
  • hx-push-url changes the current URL so it will be possible to share it
  • x-on:htmx:after-on-load Alpine.js event triggered when HTMX event is finished

Be first to know about new features and updates

Each time something new happens in Unfold, like new major features or new design components, we'll send you a newsletter. We promise not to spam you.

Django admin theme built with Tailwind CSS to bring modern look and feel to your admin interface. Already contains several built-in features for smooth developer experience.

© 2023 - 2024 Created by unfoldadmin.com. All rights reserved.