HTMX integration for ASGI applications. Works with Starlette, FastAPI, Quart -- or any other web framework supporting ASGI that exposes the ASGI scope
. Inspired by django-htmx.
Table of contents
NOTE: This is alpha software. Please be sure to pin your dependencies.
pip install asgi-htmx==0.1.*
First, ensure HTMX is installed.
For example, download a copy of htmx.min.js
, add it to your static files, then add the script tag to templates:
<script src="{{ url_for('static', path='/js/htmx.min.js') }}" defer></script>
Now, install HtmxMiddleware
onto the ASGI app:
-
Using Starlette:
from asgi_htmx import HtmxMiddleware from starlette.middleware import Middleware app = Starlette( middleware=[ ..., Middleware(HtmxMiddleware), ..., ], )
-
Using FastAPI:
from asgi_htmx import HtmxMiddleware from fastapi import FastAPI app = FastAPI() app.add_middleware(HtmxMiddleware)
You can now access scope["htmx"]
(an instance of HtmxDetails
) in endpoints:
# `HtmxRequest` makes code editors type-check `request.scope["htmx"]`
from asgi_htmx import HtmxRequest as Request
from .resources import templates
async def home(request: Request):
template = "home.html"
context = {"request": request}
if (htmx := request.scope["htmx"]):
template = "partials/items.html"
context["boosted"] = htmx.boosted # ...
return templates.TemplateResponse(template, context)
See examples for full working example code.
An ASGI middleware that sets scope["htmx"]
to an instance of HtmxDetails
(scope
refers to the ASGI scope).
app = HtmxMiddleware(app)
A helper that provides shortcuts for accessing HTMX-specific request headers.
htmx = HtmxDetails(scope)
__bool__() -> bool
- ReturnTrue
if the request was made using HTMX (HX-Request
is present),False
otherwise.boosted: bool
- Mirrors theHX-Boosted
header:True
if the request is via an element with thehx-boost
attribute.current_url: str | None
- Mirrors theHX-Current-URL
header: The current URL of the browser, orNone
for non-HTMX requests.history_restore_request: str
- Mirrors theHX-History-Restore-Request
header:True
if the request is for history restoration after a miss in the local history cache.prompt: str | None
- MirrorsHX-Prompt
: The user response tohx-prompt
if it was used, orNone
.target: str | None
- MirrorsHX-Target
: Theid
of the target element if it exists, orNone
.trigger: str | None
- MirrorsHX-Trigger
: Theid
of the trigger element if it exists, orNone
.trigger_name: str | None
- MirrorsHX-Trigger-Name
: Thename
of the trigger element if it exists, orNone
.triggering_event: Any | None
- MirrorsTriggering-Event
, which is set by the event-header extension: The deserialized JSON representation of the event that triggered the request if it exists, orNone
.
For Starlette-based frameworks, use this instead of the standard starlette.requests.Request
so that code editors understand that request.scope["htmx"]
contains an HtmxDetails
instance:
from asgi_htmx import HtmxRequest as Request
async def home(request: Request):
reveal_type(request.scope["htmx"]) # Revealed type is 'HtmxDetails'
MIT