agentsclimarketplace

Litestar htmx

Skill litestar-org/litestar-skills/skills/litestar-htmx

Opinionated first-party agent skills, plugins, subagents, slash commands, and MCP servers for the Litestar framework ecosystem — publishable to Claude Code, Gemini CLI, Codex CLI, Cursor, OpenCode, and VS Code/Copilot from a single repo.

Install
npx -y skills add litestar-org/litestar-skills --skill litestar-htmx

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 13 stars13 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Auto-activate for litestar_htmx, HTMXPlugin, HTMXConfig, HTMXRequest, HTMXTemplate, HXLocation, ReplaceUrl, TriggerEvent, HX-* headers, or Litestar partial HTML. Not for generic browser-side HTMX or Litestar Vite JSON templating — those are client concerns.

SKILL.md

12.2 KB, as published. Nobody here has run it

litestar-htmx

litestar-htmx is the standalone Litestar integration for HTMX. Version 0.5.0 ships the litestar_htmx import package with request helpers, an optional application plugin, template responses, and typed HTMX response-header helpers.

Code Style Rules

  • Import the integration from litestar_htmx, never litestar.plugins.htmx; Litestar no longer owns this package's import surface.
  • Use HTMXRequest when handlers inspect HTMX request headers.
  • Return template fragments from HTMX endpoints; keep full-page routes and fragment routes distinct.
  • Use the response classes for HX-* headers; do not assemble those headers by hand.
  • Keep browser-side HTMX extensions separate from this server package.

Quick Reference

Configure the plugin

from litestar import Litestar
from litestar_htmx import HTMXPlugin

app = Litestar(
    route_handlers=[...],
    plugins=[HTMXPlugin()],
)

HTMXPlugin() is the convenience path: it registers the package's request and response types. Its default HTMXConfig(set_request_class_globally=True) sets HTMXRequest only when the application does not already have a request class.

Preserve an existing custom request class by extending HTMXRequest:

from litestar_htmx import HTMXRequest


class ApplicationRequest(HTMXRequest):
    """Application request with HTMX helpers."""

If the application only needs response helpers, use HTMXConfig(set_request_class_globally=False). To inspect request.htmx, configure HTMXRequest (or a subclass) as the application request class. The plugin never replaces a request class already present in AppConfig.

The plugin itself is optional. Applications can instead set request_class=HTMXRequest directly and return the response subclasses without registering HTMXPlugin.

Inspect request headers

request.htmx is always an HTMXDetails object. Its truth value is True only when HX-Request is exactly "true".

from litestar import get
from litestar.response import Template
from litestar_htmx import HTMXRequest


@get("/items")
async def list_items(request: HTMXRequest) -> Template:
    template_name = "partials/item-list.html" if request.htmx else "pages/items.html"
    return Template(template_name=template_name, context={"items": []})

Available request helpers:

PropertySourceResult
bool(request.htmx)HX-RequestWhether this is an HTMX request
request.htmx.boostedHX-Boostedbool
request.htmx.current_urlHX-Current-URLstr | None
request.htmx.current_url_abs_pathHX-Current-URLSame-origin path, query, and fragment, or None
request.htmx.history_restore_requestHX-History-Restore-Requestbool
request.htmx.promptHX-Promptstr | None
request.htmx.targetHX-Targetstr | None
request.htmx.triggerHX-Triggerstr | None
request.htmx.trigger_nameHX-Trigger-Namestr | None
request.htmx.triggering_eventTriggering-EventDecoded JSON value, or None

triggering_event is supplied by HTMX's event-header extension. Malformed JSON resolves to None. Headers accompanied by <Header>-URI-AutoEncoded: true are URL-decoded before use.

Return template fragments with HTMX headers

HTMXTemplate extends Litestar's Template. Annotate handlers with Template, then pass normal Template arguments plus HTMX-specific options:

from litestar import get
from litestar.response import Template
from litestar_htmx import HTMXTemplate


@get("/items/fragment")
async def item_list() -> Template:
    return HTMXTemplate(
        template_name="partials/item-list.html",
        context={"items": []},
        push_url=False,
        re_swap="outerHTML",
        re_target="#item-list",
        trigger_event="itemsLoaded",
        params={"count": 0},
        after="receive",
    )

trigger_event, params, and after form one event declaration. When triggering an event, set after to "receive", "settle", or "swap".

Response helper signatures

All helpers are exported from litestar_htmx and litestar_htmx.response.

HelperConstructorBehavior
HXStopPollingHXStopPolling()Returns status 286
ClientRedirectClientRedirect(redirect_to)Sets HX-Redirect; no Location header
ClientRefreshClientRefresh()Sets HX-Refresh: true
PushUrlPushUrl(content, push_url, **response_kwargs)Sets HX-Push-Url
ReplaceUrlReplaceUrl(content, replace_url, **response_kwargs)Sets HX-Replace-Url
ReswapReswap(content, method, **response_kwargs)Sets HX-Reswap
RetargetRetarget(content, target, **response_kwargs)Sets HX-Retarget
TriggerEventTriggerEvent(content, name, after, params=None, **response_kwargs)Sets the selected HX-Trigger* header
HXLocationHXLocation(redirect_to, source=None, event=None, target=None, select=None, swap=None, hx_headers=None, values=None, **response_kwargs)Sets JSON in HX-Location

push_url=False and replace_url=False emit "false" to prevent the corresponding history update.

Soft navigation with HXLocation

Use HXLocation for an HTMX navigation request without a full-page reload. select chooses a fragment from the fetched response before it is swapped:

from litestar import post
from litestar_htmx import HXLocation


@post("/items")
async def create_item() -> HXLocation:
    return HXLocation(
        redirect_to="/items",
        source="#create-item",
        event="submit",
        target="#content",
        select="#item-list",
        swap="innerHTML",
        hx_headers={"X-View": "compact"},
        values={"created": "true"},
    )

The response uses status 200, carries HX-Location, and removes the ordinary Location header.

Trigger an event while returning content

TriggerEvent requires the response content, event name, and after phase:

from litestar import post
from litestar_htmx import TriggerEvent


@post("/items")
async def create_item() -> TriggerEvent[str]:
    return TriggerEvent(
        content="<li>Saved</li>",
        name="itemCreated",
        after="swap",
        params={"id": 42},
        media_type="text/html",
    )

Prefer HTMXTemplate when the content is HTML assembled from application data.

Litestar Vite is a separate client layer

The standalone package owns Python request parsing and response headers:

from litestar_htmx import HTMXPlugin, HTMXRequest, HTMXTemplate

Litestar Vite's hx-ext="litestar" JSON templating and CSRF integration come from the separate litestar-vite-plugin/helpers JavaScript export. They are not installed, registered, or enabled by HTMXPlugin(). Use them only when the project already uses Litestar Vite and needs client-side JSON swaps. See Litestar Vite Integration.

<workflow>

Workflow

  1. Check the project's installed litestar-htmx version and existing request class.
  2. Register HTMXPlugin() or set request_class=HTMXRequest directly. Extend HTMXRequest when the application needs custom request behavior.
  3. Separate full-page endpoints from fragment endpoints. Branch on request.htmx only when one URL intentionally supports both.
  4. Render fragments with Template or HTMXTemplate.
  5. Select the narrow response helper matching the required HTMX header.
  6. Configure CSRF protection for every state-changing HTMX request.
  7. Test the response body, status, and exact HX-* header.
  8. Add Litestar Vite's client extension only for bundled assets, CSRF header injection, or JSON templating.
</workflow> <guardrails>

Guardrails

  • Use litestar_htmx, never litestar.plugins.htmx. The 0.5.0 package is a standalone distribution with its own public import root.
  • Pass every required response-helper argument. TriggerEvent requires content, name, and after; PushUrl, ReplaceUrl, Reswap, and Retarget also require content.
  • Use select= on HXLocation to choose returned content. Do not confuse it with target=, which chooses the receiving element.
  • Do not assume HTMXPlugin overrides an existing request class. It preserves a non-null AppConfig.request_class.
  • Do not treat request.htmx as an optional object. Test its truth value to identify HTMX requests.
  • Do not send a normal redirect for HXLocation or ClientRedirect. These helpers return 200 with HTMX response headers.
  • Do not attribute hx-ext="litestar" to litestar-htmx. That browser extension ships with Litestar Vite's npm package.
  • Do not return unsanitized, concatenated HTML. Render templates so escaping and template caching remain intact.
</guardrails> <validation>

Validation Checkpoint

  • Imports use litestar_htmx, not litestar.plugins.htmx
  • HTMXPlugin() or request_class=HTMXRequest wires request helpers
  • A custom global request class extends HTMXRequest
  • Full pages and HTMX fragments have explicit boundaries
  • TriggerEvent includes content, name, and a valid after value
  • ReplaceUrl uses replace_url=, not push_url=
  • HXLocation.select and HXLocation.target serve distinct purposes
  • State-changing HTMX requests include the application's CSRF token
  • Tests assert the exact status, body, and HX-* response header
  • Litestar Vite client-extension guidance is identified as a separate layer
</validation> <example>

Example

Return a fragment, retarget the swap, prevent a history update, and verify the HTMX response:

from litestar import Controller, get
from litestar.response import Template
from litestar_htmx import HTMXRequest, HTMXTemplate


class ItemController(Controller):
    path = "/items"

    @get("/")
    async def index(self, request: HTMXRequest) -> Template:
        items = [{"id": 1, "name": "Widget"}]
        if request.htmx:
            return HTMXTemplate(
                template_name="partials/item-list.html",
                context={"items": items},
                re_target="#item-list",
                re_swap="outerHTML",
                push_url=False,
            )
        return Template(template_name="pages/items.html", context={"items": items})
async def test_htmx_item_list(client) -> None:
    response = await client.get(
        "/items/",
        headers={"HX-Request": "true", "HX-Target": "item-list"},
    )

    assert response.status_code == 200
    assert response.headers["HX-Retarget"] == "#item-list"
    assert response.headers["HX-Reswap"] == "outerHTML"
    assert response.headers["HX-Push-Url"] == "false"
    assert "<html" not in response.text
</example>

References Index

  • Litestar Vite Integration — Keep the standalone Python package distinct from Litestar Vite's browser extension.
  • Litestar — Application setup, templates, and lifecycle fundamentals.
  • Litestar Vite — Asset bundling, template mode, HMR, and the client helper package.
  • Litestar Testing — Async clients and application fixtures.

Official References

Shared Styleguide Baseline

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.