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
HxRequestthat is being rendered.The
closeHxModal(close-hx-modalin the Html above) event is used to close the modal - this is triggered by theHxModalHxRequest(the code above is using Alpine.js to close the modal).
Add Settings to settings.py
HX_REQUESTS_MODAL_TEMPLATE in settings to the path of the modal template.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-targetof 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:
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)
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>