Skip to content

HTMX Support

AgenticAPI integrates with HTMX for building interactive web applications with partial page updates. Endpoints can detect HTMX requests and return HTML fragments instead of full pages.

How It Works

Browser (with htmx.js)
  → Sends request with HX-Request: true header
  → AgenticAPI detects HTMX via HtmxHeaders (auto-injected)
  → Handler returns HTMLResult (fragment or full page)
  → HTMX swaps the fragment into the page

HtmxHeaders

Declare HtmxHeaders in your handler signature — it's auto-injected like AgentTasks and UploadedFiles:

from agenticapi import AgenticApp, HtmxHeaders, HTMLResult

app = AgenticApp()

@app.agent_endpoint(name="items")
async def items(intent, context, htmx: HtmxHeaders):
    if htmx.is_htmx:
        # Return just the fragment for partial swap
        return HTMLResult(content="<li>Item 1</li><li>Item 2</li>")
    # Full page for direct browser navigation
    return HTMLResult(content="""
        <html>
        <head><script src="https://unpkg.com/htmx.org"></script></head>
        <body>
            <ul hx-get="/agent/items" hx-trigger="load">Loading...</ul>
        </body>
        </html>
    """)

Available Headers

Property Type HTMX Header Description
is_htmx bool HX-Request True if request came from HTMX
boosted bool HX-Boosted True if from an hx-boost element
target str \| None HX-Target ID of the target element
trigger str \| None HX-Trigger ID of the trigger element
trigger_name str \| None HX-Trigger-Name Name of the trigger element
current_url str \| None HX-Current-URL Current browser URL
prompt str \| None HX-Prompt User response to hx-prompt

Response Headers

Use htmx_response_headers() to control HTMX client-side behavior:

from agenticapi.interface.htmx import htmx_response_headers

@app.agent_endpoint(name="add_item")
async def add_item(intent, context, htmx: HtmxHeaders):
    # Tell HTMX to trigger a client event and use beforeend swap
    headers = htmx_response_headers(
        trigger="itemAdded",
        reswap="beforeend",
    )
    return HTMLResult(content="<li>New item</li>", headers=headers)

Available Response Headers

Parameter HTMX Header Description
trigger HX-Trigger Trigger client-side events
trigger_after_settle HX-Trigger-After-Settle Trigger after settling step
trigger_after_swap HX-Trigger-After-Swap Trigger after swap step
redirect HX-Redirect Redirect the browser
refresh HX-Refresh Full page refresh
retarget HX-Retarget Override swap target selector
reswap HX-Reswap Override swap strategy
push_url HX-Push-Url Push URL to browser history
replace_url HX-Replace-Url Replace current URL

Full Example: Todo App

from agenticapi import AgenticApp, HtmxHeaders, HTMLResult
from agenticapi.interface.htmx import htmx_response_headers

app = AgenticApp(title="HTMX Todo")
todos = ["Buy milk", "Write tests"]

@app.agent_endpoint(name="list")
async def todo_list(intent, context, htmx: HtmxHeaders):
    items_html = "".join(f"<li>{t}</li>" for t in todos)
    if htmx.is_htmx:
        return HTMLResult(content=items_html)
    return HTMLResult(content=f"""
        <html>
        <head><script src="https://unpkg.com/htmx.org"></script></head>
        <body>
            <ul id="todos">{items_html}</ul>
            <input name="intent" hx-post="/agent/add"
                   hx-target="#todos" hx-swap="beforeend">
        </body>
        </html>
    """)

@app.agent_endpoint(name="add")
async def todo_add(intent, context, htmx: HtmxHeaders):
    todos.append(intent.raw)
    headers = htmx_response_headers(trigger="todoAdded")
    return HTMLResult(content=f"<li>{intent.raw}</li>", headers=headers)

When to Use HTMX vs JSON

Use case Response type
API for programmatic clients dict or AgentResponse (JSON)
Full HTML page HTMLResult
HTMX partial update HTMLResult (fragment) with htmx.is_htmx check
Plain text (status, logs) PlainTextResult
File download FileResult

All response types work in the same app — each endpoint chooses independently.

Example

See examples/12_htmx/ for a complete HTMX todo app with list, add, search, and toggle endpoints.