JavaScript

The django-htmx-plus.js ES module provides client-side integration between HTMX and Bootstrap 5 modals/offcanvases.

Overview

The JavaScript module automatically handles opening and closing Bootstrap 5 modals and offcanvases when HTMX swaps content. This eliminates the need for manual JavaScript coordination between HTMX and Bootstrap components.

Features

  • Auto-show modals when HTMX swaps content

  • Auto-hide modals on empty responses

  • Auto-reset modal body when closed

  • Full support for Bootstrap 5 Modals and Offcanvases

  • Content Security Policy (CSP) nonce support

Installation

Add the template tag to your base template, after Bootstrap JS:

{% load django_htmx_plus %}

<!-- After Bootstrap JS -->
{% htmx_plus_script %}

This renders:

<script src="/static/django_htmx_plus/django-htmx-plus.js" type="module"></script>

With optional CSP nonce if present in template context:

<script src="/static/django_htmx_plus/django-htmx-plus.js" type="module" nonce="..."></script>

Requirements

  • Bootstrap 5 available as an ES module

  • HTMX library loaded before the script

  • Either an import map or bundler that provides Bootstrap as an ES module

Setup with Import Map

If loading Bootstrap as a global script, use an import map to make it available as an ES module:

<script type="importmap">
{
  "imports": {
    "@popperjs/core": "{% static '@popperjs/core/dist/esm/index.js' %}",
    "bootstrap": "{% static 'bootstrap/js/index.esm.js' %}",
  }
}
</script>

{% htmx_plus_script %}

Setup with Bundler

If using a bundler (Webpack, Vite, etc.), ensure Bootstrap is installed as an npm package and the bundler resolves the import correctly.

Offcanvas Configuration

Mark Offcanvas Elements

Add data-htmx-plus-offcanvas="<target_id>" to the offcanvas root element:

<!-- Bootstrap Offcanvas -->
<div class="offcanvas offcanvas-end" tabindex="-1" id="flyout-end" data-htmx-plus-offcanvas="flyout-end" aria-labelledby="flyout-label" aria-modal="true" role="dialog">
</div>

Create HTMX Triggers

<button class="btn btn-secondary" hx-get="/menu/" hx-target="#flyout-end">
    Open Menu
</button>

Behavior is the same as modals – content triggers show, empty response triggers close.

CSP Nonce Support

If using Content Security Policy, pass a nonce variable in your template context:

context = {
    "nonce": generate_nonce(),  # Your nonce generation function
}

The template tag automatically includes the nonce in the script tag:

<script src="..." type="module" nonce="your-nonce-value"></script>