Skip to content

Snippets and Examples

The extension contributes secure Django-first HTMX patterns for django-html documents. Type a prefix to insert the snippet, then move through its editable placeholders.

Mutating forms include Django's CSRF token. The examples use HTMX syntax shared by the supported HTMX 2 and HTMX 4 catalogs. See Core Django response contracts for matching view and response examples.

Prefixes

Prefix Classification Description
htmx-get Common Django URL-backed HTMX GET button
htmx-post Common CSRF-safe Django form submitted through HTMX
htmx-delete Common CSRF-safe Django delete form submitted through POST
htmx-search Common Debounced Django HTMX search input
htmx-form-validation Common Django form replaced with server-rendered validation state
htmx-file-upload Curated recipe CSRF-safe multipart file upload with a status target
htmx-bulk-actions Curated recipe CSRF-safe bulk action form for Django objects
htmx-dependent-dropdown Curated recipe Django select that loads options for a dependent field
htmx-status-form Curated recipe HTMX 4 Django form with status-specific validation handling
htmx-infinite Common Load the next Django page when revealed
htmx-poll Curated recipe Poll a Django view until work is complete
htmx-lazy Common Load a Django fragment when its placeholder appears
htmx-boost-nav Curated recipe Progressively enhance Django navigation with history updates
htmx-progress Curated recipe Poll server-rendered progress for a Django task
htmx-click-to-edit Common Replace a Django object summary with an edit form
htmx-table-row Curated recipe Replace a Django table row with server-rendered editing controls
htmx-dialog Curated recipe Load a script-free non-modal dialog from a Django view
htmx-modal Curated recipe Load a Django view into a fixed CSS-only modal overlay
htmx-tabs Curated recipe Replace server-rendered tabs and selected state
htmx-morph Curated recipe HTMX 4 state-preserving refresh
htmx-oob-swap Common Update a second region from a Django HTMX response
htmx-toast Curated recipe Append an accessible notification from an HTMX response
htmx-partial-response Curated recipe HTMX 4 response fragment with explicit target and swap
partialdef Django 6 Define a Django 6 template partial
partialdef-inline Django 6 Define and render an inline Django 6 template partial
partial Django 6 Render a same-file Django 6 template partial

Requests and forms

htmx-get

Django URL-backed HTMX GET button.

Classification: Common

<button type="button" hx-get="{% url 'view-name' %}" hx-target="#content" hx-swap="innerHTML">
  Load
</button>

Endpoint or context: The view returns the HTML fragment that should replace the selected target.

htmx-post

CSRF-safe Django form submitted through HTMX.

Classification: Common

<form method="post" action="{% url 'view-name' %}"
      hx-post="{% url 'view-name' %}"
      hx-target="#content" hx-swap="innerHTML">
  {% csrf_token %}
  <!-- Add content here. -->
</form>

Endpoint or context: The POST view validates the submitted fields and returns the replacement fragment for the selected target.

htmx-delete

CSRF-safe Django delete form submitted through POST.

Classification: Common

<form method="post" action="{% url 'delete-view' object.pk %}"
      hx-post="{% url 'delete-view' object.pk %}"
      hx-confirm="Are you sure?"
      hx-target="closest .item"
      hx-swap="outerHTML">
  {% csrf_token %}
  <button type="submit">Delete</button>
</form>

Endpoint or context: The POST view performs the deletion and returns either an empty response or replacement markup for the item.

Debounced Django HTMX search input.

Classification: Common

<input type="search" name="q"
       hx-get="{% url 'search-view' %}"
       hx-trigger="input changed delay:300ms, search"
       hx-target="#results">

Endpoint or context: The search view reads the input value and returns the current result-list fragment.

htmx-form-validation

Django form replaced with server-rendered validation state.

Classification: Common

<form method="post" action="{% url 'validate-view' %}"
      hx-post="{% url 'validate-view' %}"
      hx-target="this" hx-swap="outerHTML">
  {% csrf_token %}
  {{ form.as_p }}
  <button type="submit">Save</button>
</form>

Endpoint or context: The view returns the complete bound form with HTTP 200 when invalid, or a complete success fragment when valid.

htmx-file-upload

CSRF-safe multipart file upload with a status target.

Classification: Curated recipe

<form method="post" action="{% url 'upload-view' %}" enctype="multipart/form-data"
      hx-post="{% url 'upload-view' %}"
      hx-encoding="multipart/form-data"
      hx-target="#upload-result"
      hx-swap="innerHTML" hx-indicator="#upload-indicator">
  {% csrf_token %}
  <label for="upload-file">Choose a file</label>
  <input id="upload-file" type="file" name="file" required>
  <button type="submit">Upload</button>
  <span id="upload-indicator" class="htmx-indicator" role="status">Uploading…</span>
</form>
<div id="upload-result" aria-live="polite"></div>

Endpoint or context: The upload view reads request.FILES, validates the file, and returns success or error markup for the upload-result target.

htmx-bulk-actions

CSRF-safe bulk action form for Django objects.

Classification: Curated recipe

<form method="post" action="{% url 'bulk-view' %}"
      hx-post="{% url 'bulk-view' %}"
      hx-target="#items-body"
      hx-swap="outerHTML">
  {% csrf_token %}
  <table>
    <thead><tr><th scope="col">Select</th><th scope="col">Item</th></tr></thead>
    <tbody id="items-body">
      {% for object in objects %}
        <tr>
          <td><input type="checkbox" name="selected" value="{{ object.pk }}" aria-label="Select {{ object }}"></td>
          <td>{{ object }}</td>
        </tr>
      {% endfor %}
    </tbody>
  </table>
  <button type="submit">Apply to selected</button>
</form>

Endpoint or context: The POST view processes every selected value and returns a complete tbody element with the same id.

htmx-dependent-dropdown

Django select that loads options for a dependent field.

Classification: Curated recipe

<label for="parent-select">Category</label>
<select id="parent-select" name="category"
        hx-get="{% url 'options-view' %}"
        hx-trigger="change"
        hx-target="#dependent-select"
        hx-swap="innerHTML">
  <!-- Add content here. -->
</select>
<label for="dependent-select">Option</label>
<select id="dependent-select" name="option"></select>

Endpoint or context: The options view reads the selected parent value and returns option elements for the dependent select.

htmx-status-form

HTMX 4 Django form with status-specific validation handling.

Classification: Curated recipe

<form method="post" action="{% url 'view-name' %}"
      hx-post="{% url 'view-name' %}" hx-target="#result"
      hx-status:422="swap:innerHTML target:#errors" hx-status:5xx="swap:none">
  {% csrf_token %}
  <div id="errors" role="alert"></div>
  <!-- Add content here. -->
  <button type="submit">Save</button>
</form>
<div id="result"></div>

Endpoint or context: Requires HTMX 4. Return validation HTML with status 422, and success HTML for the result container. Server error responses do not swap.

Loading and navigation

htmx-infinite

Load the next Django page when revealed.

Classification: Common

{% if page_obj.has_next %}
  <div hx-get="?page={{ page_obj.next_page_number }}"
       hx-trigger="revealed"
       hx-target="this" hx-swap="outerHTML"
       role="status">
    Loading…
  </div>
{% endif %}

Endpoint or context: The list view returns the next result fragment followed by a new next-page trigger when another page exists.

htmx-poll

Poll a Django view until work is complete.

Classification: Curated recipe

<div hx-get="{% url 'status-view' task.pk %}"
     hx-trigger="every 5s"
     hx-target="this"
     hx-swap="outerHTML"
     role="status" aria-live="polite">
  Waiting…
</div>

Endpoint or context: The status view returns the same polling region while work continues and omits hx-trigger after completion.

htmx-lazy

Load a Django fragment when its placeholder appears.

Classification: Common

<section hx-get="{% url 'fragment-view' %}"
         hx-trigger="load"
         hx-target="this"
         hx-swap="outerHTML"
         aria-busy="true">
  <p class="htmx-indicator" role="status">Loading…</p>
</section>

Endpoint or context: The fragment view returns the complete replacement section without aria-busy.

htmx-boost-nav

Progressively enhance Django navigation with history updates.

Classification: Curated recipe

<nav aria-label="Primary">
  <a href="{% url 'home' %}" hx-boost="true"
     hx-target="#main-content" hx-select="#main-content"
     hx-swap="outerHTML" hx-push-url="true">Home</a>
  <!-- Add content here. -->
</nav>
<main id="main-content" tabindex="-1"></main>

Endpoint or context: Each linked view returns a normal full page containing the same main-content element, which hx-select extracts.

htmx-progress

Poll server-rendered progress for a Django task.

Classification: Curated recipe

<div hx-get="{% url 'progress-view' task.pk %}"
     hx-trigger="every 1s"
     hx-target="this"
     hx-swap="outerHTML"
     role="status" aria-live="polite">
  <label for="task-progress">Progress</label>
  <progress id="task-progress" value="{{ task.progress }}" max="100">{{ task.progress }}%</progress>
</div>

Endpoint or context: The progress view returns updated markup and omits hx-trigger when the task reaches a terminal state.

Editing and UI

htmx-click-to-edit

Replace a Django object summary with an edit form.

Classification: Common

<article>
  <h2>{{ object }}</h2>
  <button type="button" hx-target="closest article" hx-swap="outerHTML" hx-get="{% url 'edit-view' object.pk %}">Edit</button>
</article>

Endpoint or context: The edit view returns a CSRF-protected form that targets and replaces itself after submission.

htmx-table-row

Replace a Django table row with server-rendered editing controls.

Classification: Curated recipe

<tr id="item-{{ object.pk }}">
  <th scope="row">{{ object }}</th>
  <td><button type="button" hx-target="closest tr" hx-swap="outerHTML" hx-get="{% url 'edit-view' object.pk %}">Edit</button></td>
</tr>

Endpoint or context: The edit view returns a complete replacement row containing a CSRF-protected update form.

htmx-dialog

Load a script-free non-modal dialog from a Django view.

Classification: Curated recipe

<button type="button" hx-get="{% url 'dialog-view' object.pk %}"
        hx-target="#dialog"
        hx-swap="outerHTML"
        aria-controls="dialog">
  Open dialog
</button>
<dialog id="dialog" aria-labelledby="dialog-title"></dialog>

Endpoint or context: The view returns a dialog with the same id, the open attribute, a labelled title, and a native method="dialog" close form; it is non-modal without showModal().

htmx-modal

Load a Django view into a fixed CSS-only modal overlay.

Classification: Curated recipe

<button type="button" hx-get="{% url 'modal-view' %}"
        hx-target="#modal" hx-swap="innerHTML"
        aria-haspopup="dialog" aria-controls="modal">
  Open modal
</button>
<div id="modal" class="modal-container" role="dialog" aria-modal="true" aria-labelledby="modal-title"></div>

Endpoint or context: The modal view returns the overlay markup with underlay/close controls that target the same container and swap it empty to close; no JavaScript is required.

htmx-tabs

Replace server-rendered tabs and selected state.

Classification: Curated recipe

<section id="tabs" aria-label="Sections">
  <nav role="tablist">
    <a id="tabs-overview" role="tab" aria-selected="true"
       aria-controls="tabs-panel"
       href="{% url 'tabs-view' 'overview' %}"
       hx-get="{% url 'tabs-view' 'overview' %}"
       hx-target="#tabs" hx-swap="outerHTML" hx-push-url="true">
      Overview
    </a>
    <!-- Add content here. -->
  </nav>
  <div id="tabs-panel" role="tabpanel" aria-labelledby="tabs-overview">
    {{ tab_content }}
  </div>
</section>

Endpoint or context: The tabs view returns the complete section with updated tablist, aria-selected state, and panel content.

htmx-morph

HTMX 4 state-preserving refresh.

Classification: Curated recipe

<section id="live-region" hx-get="{% url 'fragment-view' %}"
         hx-trigger="every 5s" hx-swap="innerMorph">
  <!-- Add content here. -->
</section>

Endpoint or context: Requires HTMX 4. The view returns the region contents. Use stable element IDs to help morphing preserve focus and state.

Server responses

htmx-oob-swap

Update a second region from a Django HTMX response.

Classification: Common

<section id="summary" hx-swap-oob="true">
  Updated summary
</section>

Endpoint or context: Return this fragment alongside the primary response; HTMX replaces the existing element with the matching id.

htmx-toast

Append an accessible notification from an HTMX response.

Classification: Curated recipe

<div id="notifications" hx-swap-oob="beforeend:#notifications">
  <p role="status" aria-live="polite">Saved successfully.</p>
</div>

Endpoint or context: Return this fragment with a primary response to append its status message to the existing notifications region.

htmx-partial-response

HTMX 4 response fragment with explicit target and swap.

Classification: Curated recipe

<hx-partial hx-target="#notifications" hx-swap="append">
  <!-- Add content here. -->
</hx-partial>

Endpoint or context: Requires HTMX 4. Return one or more hx-partial elements to update multiple targets. This is an HTMX response element, separate from Django partialdef template tags.

Django partials

partialdef

Define a Django 6 template partial.

Classification: Django 6

{% partialdef partial_name %}
  <!-- Add content here. -->
{% endpartialdef %}

Endpoint or context: Django 6 registers the named block as a reusable partial in the current template.

partialdef-inline

Define and render an inline Django 6 template partial.

Classification: Django 6

{% partialdef partial_name inline %}
  <!-- Add content here. -->
{% endpartialdef %}

Endpoint or context: Django 6 registers and renders the named partial at its definition site.

partial

Render a same-file Django 6 template partial.

Classification: Django 6

{% partial partial_name %}

Endpoint or context: The referenced partial must be defined in the same template or resolved through Django's supported partial syntax.