How To Use Modals

This how-to demonstrates how to use the built-in modal functionality in hx-requests to load content asynchronously into the modal. The built-in modal reduces boilerplate code and simplifies common tasks like handling forms, validation, and dynamic content updates—without full page reloads.

Define a Modal Template

To use the built in modal functionality, you need to define a modal template and set HX_REQUESTS_MODAL_TEMPLATE in settings to the path of the template.

<div class="modal fade"
     id="hx_modal"
     tabindex="-1"
     role="dialog"
     aria-hidden="true"
     style="display:block"
     @close-hx-modal.camel="bootstrap.Modal.getOrCreateInstance(document.getElementById('hx_modal')).hide()"
    >
    <div role="document" class="modal-dialog {{ modal_size_classes }}">
        <div class="modal-content">
            <div class="modal-header">
                <h5 class="modal-title">{{ title|default_if_none:""|safe }}</h5>
                <button type="button"
                        class="btn-close"
                        data-bs-dismiss="modal"
                        aria-label="Close"></button>
            </div>
            <div class="modal-body" id="hx_modal_body">
                <p>{{ body }}</p>
            </div>
        </div>
    </div>
</div>
<script>
    bootstrap.Modal.getOrCreateInstance(document.getElementById('hx_modal')).show();
</script>
Notes:
  • This is using a bootstrap modal, but any modal can be used.

  • The title, modal_size_classes and body are passed in as context from the HxRequest that is being rendered.

  • The closeHxModal (close-hx-modal in the Html above) event is used to close the modal - this is triggered by the HxModalHxRequest (the code above is using Alpine.js to close the modal).

Add Settings to settings.py

Define HX_REQUESTS_MODAL_TEMPLATE in settings to the path of the modal template.
Define HX_REQUESTS_MODAL_BODY_ID in settings to the id of the modal body (default is hx_modal_body)
HX_REQUESTS_MODAL_TEMPLATE = "path/to/your/modal_template.html"
HX_REQUESTS_MODAL_BODY_ID = "hx_modal_body" # Default is hx_modal_body

Add A Div to the Base Template

This is where the modal will be rendered.

<div id="hx_modal_container"></div>
Notes:
  • The id of the div can be anything, this is just the hx-target of the request.

Create a ModalHxRequest

class ModalExample(ModalHxRequest):
    name = "modal_example"
    GET_template = "modal_body.html" # A template to be used as the body of the modal
    title = "Modal Title" # The title of the modal
    modal_size_classes = "modal-lg" # The size of the modal (bootstrap classes example)

Trigger the Modal

<button {% hx_get "modal_example" %} hx-target="#hx_modal_container">Open Modal</button>

Note

This how-to is using a bootstrap 5 modal.

Using Forms in Modals

To use a form in a modal, you can use the FormModalHxRequest class. This class is a subclass of ModalHxRequest and has the same functionality as the FormHxRequest.

class UserFormModal(FormModalHxRequest):
    name = "user_form_modal"
    GET_template = "user_form.html" # This will be rendered as the body of the modal
    POST_template = "user_display.html"
    form_class = UserForm
Notes:
  • This is all that is needed to use a form in a modal.

  • The form will be validated and the form will be re-rendered in the modal if there are errors.

  • If the form is valid, the form will be submitted and the modal will close.

Manually Triggering The Modal To Close

If you need to manually close the modal, you can return the closeHxModal trigger from the get_triggers method.

class UserFormModal(FormModalHxRequest):
    name = "user_form_modal"
    GET_template = "user_form.html" # This will be rendered as the body of the modal
    POST_template = "user_display.html"
    form_class = UserForm

    def get_triggers(self, **kwargs) -> list:
        triggers = super().get_triggers(**kwargs)
        if some_condition:
            triggers.append("closeHxModal")
        return triggers

Setting Title and Size Dynamically

Many times you will want to set the title and size of the modal dynamically based on some condition. This can be done in two ways:

  1. By setting the title and size in the HxRequest:

class ModalExample(ModalHxRequest):
    name = "modal_example"
    GET_template = "modal_body.html" # A template to be used as the body of the modal

    def get(self, request, *args, **kwargs):
        if some_condition:
            self.title = "New Title"
            self.modal_size_classes = "modal-sm"
        else:
            self.title = "Default Title"
            self.modal_size_classes = "modal-lg"
        return super().get(request, **kwargs)
  1. Via the template tag

<button {% hx_get "modal_example" title="New Title" modal_size_classes="modal-sm" %} hx-target="#hx_modal_container">Open Modal</button>