Django HTMX
Use HTMX to keep Django templates, views, forms, permissions, and server-side validation in charge while adding focused partial-page updates. Prefer plain Django first, then add the smallest HTMX behavior that improves the workflow.
In generated django-saas-starter projects:
django-htmxis installed anddjango_htmx.middleware.HtmxMiddlewareaddsrequest.htmx.htmx.min.jsis copied from npm tofrontend/static/vendors/js/and loaded byfrontend/templates/base_app.htmlandfrontend/templates/base_landing.html.- The base templates already add
X-CSRFTokenduringhtmx:configRequestand setwindow.htmx.config.historyRestoreAsHxRequest = false. Do not duplicate this setup in feature templates. - Use Alpine.js only for browser-local state such as menus, modals, disclosure state, and lightweight transitions.
Framework-Neutral HTMX Skills
Use these skills for deeper htmx guidance, then translate back to Django forms, views, templates, permissions, and tests:
htmx-endpoint-designfor request/response contracts, targets, swaps, out-of-band updates, and events.htmx-recipesfor active search, pagination, infinite scroll, polling, dialogs, click-to-edit, boosted links, and other common patterns.htmx-securityfor XSS, sanitization, CSP, CSRF, and htmx history-cache risk.htmx-realtimefor polling, SSE, and WebSocket tradeoffs.htmx-interactivityfor Alpine.js coordination, event boundaries, and local state outside replaceable targets.htmx-js-apifor programmatic requests,htmx.process, and event wiring.
Resource Routing
Load only the files needed for the current task:
| Need | Read |
|---|---|
| Django view branching, response helpers, forms, validation | references/django-view-patterns.md |
| Template targets, swaps, OOB updates, Alpine events, recipe notes | references/template-interaction-patterns.md |
| Security rules, Django tests, response assertions, reference docs | references/testing-security.md |
Implementation Workflow
- Find the server state owner: model, queryset, form, service, permission, or session value.
- Choose the smallest URL boundary:
- Reuse an existing view with
request.htmxbranching when the full page and partial share the same query and permissions. - Create a dedicated endpoint when the interaction has a narrow component contract or different mutation rules.
- Reuse an existing view with
- Put reusable fragments in partial templates, commonly
frontend/templates/<app>/partials/...or the local app template folder. - Render the full page by including the same partial that the HTMX response returns.
- Preserve non-HTMX fallback behavior for links and forms whenever practical.
- Add tests for both normal and HTMX requests when the view branches on
request.htmx.
Django Rules
- Branch on
request.htmxonly after the same auth, permission, and data-loading path has run. - Use
@vary_on_headers("HX-Request")on cacheable views that return different full-page and partial content for the same URL. - Prefer
django_htmx.httphelpers over hand-writing HTMX headers:HttpResponseClientRedirect,HttpResponseClientRefresh,HttpResponseLocation,HttpResponseStopPolling,push_url(),replace_url(),retarget(),reswap(),reselect(), andtrigger_client_event(). - Keep Django forms as the validation source of truth. Include
{% csrf_token %}in forms even when the base HTMX header is configured. - For invalid HTMX form submissions, return a rendered bound form with normal
status
200unless the project explicitly handles4xxor422swaps. - For destructive actions, require POST unless the project has a deliberate
method override pattern for
DELETE. - Keep the ownership line clear: HTMX owns server trips, fresh HTML, history updates, and cross-component server facts; Alpine owns local-only state, keyboard/menu behavior, temporary UI state, and transitions.
- Use
hx-push-url="true"only when the new state deserves a real browser URL, and ensure the pushed URL can render a full page on direct load and refresh.
Avoid
- Do not return JSON for UI updates unless a non-HTMX API truly needs JSON.
- Do not add React, Vue, or a client router for ordinary partial updates.
- Do not place business logic in templates or browser event handlers.
- Do not create one generic "htmx endpoint" that switches behavior based on arbitrary request parameters. Use explicit URLs and views.
- Do not attach
hx-trigger="keyup"or polling without debounce, throttle, or a clear stop condition. - Do not use HTMX to bypass Django's normal authentication, authorization, CSRF, form, or message patterns.
Source: hashgraph-online/awesome-codex-plugins → plugins/LVTD-LLC/skills/skills/django-htmx/SKILL.md