Django Htmx Modal Forms
Documentation: https://django-htmx-modal-forms.readthedocs.io
Source Code: https://github.com/abe-101/django-htmx-modal-forms
A Django package that provides class-based views for handling forms in Bootstrap modals using HTMX. This package makes it easy to add create and update functionality to your Django models with a clean modal interface.
Features
- 🚀 Easy-to-use class-based views for modal forms
- ⚡ HTMX-powered for dynamic updates without page reloads
- 🎨 Bootstrap modal integration with customizable sizes
- ✨ Automatic form validation with error handling
- 🐛 Debug mode for development
Requirements
- Python 3.8+
- Django 4.2+
- django-htmx
- Bootstrap 5
- django-crispy-forms
Installation
- Install via pip:
pip install django-htmx-modal-forms
- Add to your
INSTALLED_APPS:
INSTALLED_APPS = [
...
"crispy_forms",
"crispy_bootstrap5",
"django-htmx"
"django_htmx_modal_forms",
]
- Load and include the JavaScript in your base template:
{% load htmx_modal_forms %}
<!doctype html>
<html>
<head>
<!-- Required dependencies -->
<script src="{% static 'js/bootstrap.bundle.min.js' %}"></script>
<script src="{% static 'js/htmx.min.js' %}"></script>
<!-- Modal handlers -->
{% htmx_modal_script %}
</head>
<body>
<!-- Your content -->
</body>
</html>
Quick Start
- Create your view:
from django_htmx_modal_forms import HtmxModalUpdateView
class PersonUpdateView(HtmxModalUpdateView):
model = Person
form_class = PersonForm
detail_template_name = "persons/_person_card.html"
modal_size = "lg" # Optional: sm, lg, or xl
- Add the URL pattern:
path("persons/<int:pk>/edit/", PersonUpdateView.as_view(), name="person_update"),
- Create your detail template (
_person_card.html):
<div id="person-{{ person.id }}" class="card">
<div class="card-body">
<h5 class="card-title">{{ person.name }}</h5>
<p class="card-text">{{ person.email }}</p>
</div>
</div>
Important: The wrapper element must have an ID that matches your model instance (e.g.,
id="person-{{ person.id }}")! This ID is used by the view to locate and replace the content after a successful form submission.
- Add a button to trigger the modal:
<button
hx-get="{% url 'person_update' pk=person.pk %}"
hx-target="body"
hx-swap="beforeend"
class="btn btn-primary"
>
Edit Person
</button>
That's it! When you click the edit button, a modal will appear with your form. On successful submission, the person's card will automatically update with the new information.
Advanced Usage
Custom Modal Titles
class PersonCreateView(HtmxModalCreateView):
model = Person
form_class = PersonForm
modal_title = "Add New Team Member" # Custom title
Different Modal Sizes
class PersonUpdateView(HtmxModalUpdateView):
model = Person
form_class = PersonForm
modal_size = "xl" # Available: sm, lg, xl
Debug Mode
Debug mode is automatically enabled when settings.DEBUG = True. It provides helpful console logging for:
- Modal initialization
- Event triggers
- Bootstrap/HTMX availability
- Error conditions
How It Works Behind the Scenes
The package orchestrates a series of interactions between Django, HTMX, and Bootstrap:
- When you click an edit button, HTMX makes a GET request to your view
- The view returns a Bootstrap modal containing your form and triggers the
modal:showevent - The included JavaScript initializes and displays the modal
- When submitting the form:
- If there are validation errors, the view replaces the form content with the errors
- On success:
- The view updates your model
- Renders the new content using your detail template
- Uses HTMX's out-of-band swap to replace the content using the ID you provided
- Triggers the modal to close
This approach provides a smooth user experience with minimal JavaScript while maintaining Django's server-side validation and template rendering.
[Previous content remains the same until Contributing section]
Credits
This package was inspired by Josh Karamuth's blog posts on Django + HTMX modals:
Contributing
Contributions are welcome! Please feel free to submit a Pull Request. To develop locally:
- Clone the repository
- Install dependencies:
uv sync - Run tests:
uv run pytest
Contributors ✨
Thanks goes to these wonderful people (emoji key):
Abe Hanoka 💻 🤔 📖 |
This project follows the all-contributors specification. Contributions of any kind welcome!
Credits
This package was created with Copier and the browniebroke/pypackage-template project template.
Release files for django-htmx-modal-forms 0.4.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| django_htmx_modal_forms-0.4.0.tar.gz | 15.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| django_htmx_modal_forms-0.4.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 28.1 kB
Release files / django_htmx_modal_forms-0.4.0.tar.gz
| Download URL | django_htmx_modal_forms-0.4.0.tar.gz |
|---|---|
| Size | 15.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
5cedcd8eadd71abdb8eef743fd6b08d883402576b4b983aa30145b7db20efeb2
|
|
BLAKE2b-256 checksum How to use checksums |
640216c2fa1fe030a7f9a420c8951b21bc88d2531ebe87d051d0da93e6985144
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.12.9
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Apr 11, 2025.
Transparency logRelease files / django_htmx_modal_forms-0.4.0-py3-none-any.whl
| Download URL | django_htmx_modal_forms-0.4.0-py3-none-any.whl |
|---|---|
| Size | 12.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
b2f2ccc6fd2b4004bcd59f07c3b0815ed468d109ecd5ec8709587134201bce67
|
|
BLAKE2b-256 checksum How to use checksums |
abc9a996acf36fe02e0c530a3a7c98731af035bd6347440ff5fb306924f42cdc
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.12.9
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Apr 11, 2025.
Transparency log