Skip to content
Skillv1.0.0

htmx

htmx gives you access to AJAX, CSS transitions, WebSockets, and Server-Sent Events directly in HTML using attributes. It enables dynamic web UIs without writing JavaScript by letting any element issue

by terminalskills(0) 0 installs
Free
Sign in to install

Free account. Installing gives you the manifest plus copy-paste snippets.

See reviews

About

Imported from terminalskills/skills (skills/htmx/SKILL.md). Install upstream with npx skills add terminalskills/skills --skill htmx. Copyright stays with the author (Apache-2.0).

htmx

htmx extends HTML with attributes like hx-get, hx-post, hx-swap, and hx-trigger to make any element capable of issuing HTTP requests and updating the DOM. The server returns HTML fragments, not JSON.

Installation

<!-- index.html — add htmx via CDN or npm -->
<script src="https://unpkg.com/htmx.org@2.0.4"></script>
<!-- Or: npm install htmx.org -->

Core Attributes

<!-- templates/core-demo.html — fundamental htmx attributes -->

<!-- GET request, replace inner HTML of target -->
<button hx-get="/api/articles" hx-target="#article-list" hx-swap="innerHTML">
  Load Articles
</button>
<div id="article-list"></div>

<!-- POST form without page reload -->
<form hx-post="/api/articles" hx-target="#article-list" hx-swap="afterbegin">
  <input name="title" placeholder="Title" required />
  <textarea name="body" placeholder="Body" required></textarea>
  <button type="submit">Create</button>
</form>

<!-- DELETE with confirmation -->
<button hx-delete="/api/articles/42" hx-confirm="Are you sure?" hx-target="closest article" hx-swap="outerHTML swap:500ms">
  Delete
</button>

Swap Strategies

<!-- templates/swap-strategies.html — different ways to insert content -->

<!-- Replace inner content (default) -->
<div hx-get="/fragment" hx-swap="innerHTML">Replace my contents</div>

<!-- Replace entire element -->
<div hx-get="/fragment" hx-swap="outerHTML">Replace me entirely</div>

<!-- Append/prepend to list -->
<div id="list">
  <button hx-get="/more" hx-target="#list" hx-swap="beforeend">Load More</button>
</div>

<!-- Swap with transition delay -->
<div hx-get="/fragment" hx-swap="innerHTML settle:300ms">With transition</div>

<!-- Out-of-band swaps (update multiple elements) -->
<!-- Server returns: -->
<!-- <div id="notification" hx-swap-oob="innerHTML">New notification!</div> -->
<!-- <div id="count" hx-swap-oob="innerHTML">43</div> -->

Triggers

<!-- templates/triggers.html — custom event triggers -->

<!-- Trigger on input change with debounce -->
<input type="search" name="q"
  hx-get="/search"
  hx-trigger="input changed delay:300ms"
  hx-target="#results" />
<div id="results"></div>

<!-- Trigger on intersection (lazy loading) -->
<div hx-get="/more-articles"
  hx-trigger="intersect once"
  hx-swap="afterend">
  Loading...
</div>

<!-- Trigger on custom event -->
<div hx-get="/notifications" hx-trigger="newMessage from:body">
  Notifications
</div>

<!-- Polling -->
<div hx-get="/api/status" hx-trigger="every 5s">
  Status: checking...
</div>

Server Responses (Python/Django Example)

# views.py — server returns HTML fragments, not JSON
from django.shortcuts import render
from django.http import HttpResponse

def article_list(request):
    articles = Article.objects.filter(published=True)[:20]
    return render(request, "partials/article_list.html", {"articles": articles})

def create_article(request):
    form = ArticleForm(request.POST)
    if form.is_valid():
        article = form.save()
        return render(request, "partials/article_card.html", {"article": article})
    return render(request, "partials/article_form.html", {"form": form}, status=422)

def delete_article(request, pk):
    Article.objects.filter(pk=pk).delete()
    return HttpResponse("")  # Empty response removes element with outerHTML swap
<!-- templates/partials/article_card.html — HTML fragment returned by server -->
<article id="article-{{ article.id }}">
  <h2>{{ article.title }}</h2>
  <p>{{ article.body|truncatewords:30 }}</p>
  <button hx-delete="/api/articles/{{ article.id }}"
    hx-target="#article-{{ article.id }}"
    hx-swap="outerHTML swap:300ms"
    hx-confirm="Delete this article?">
    Delete
  </button>
</article>

Indicators

<!-- templates/indicators.html — loading indicators -->

<!-- Show spinner during request -->
<button hx-get="/slow-endpoint" hx-indicator="#spinner">
  Load Data
</button>
<span id="spinner" class="htmx-indicator">Loading...</span>

<!-- CSS (htmx adds .htmx-request class during requests) -->
<style>
  .htmx-indicator { display: none; }
  .htmx-request .htmx-indicator { display: inline; }
  .htmx-request.htmx-indicator { display: inline; }
</style>

Headers and Request Config

<!-- templates/request-config.html — request customization -->

<!-- Include extra values -->
<button hx-post="/api/vote" hx-vals='{"article_id": 42, "vote": "up"}'>
  Upvote
</button>

<!-- Include values from other elements -->
<input id="search-input" name="q" />
<button hx-get="/search" hx-include="#search-input">Search</button>

<!-- Push URL to browser history -->
<a hx-get="/articles/my-article" hx-push-url="true" hx-target="#content">
  My Article
</a>

Server-Sent Events

<!-- templates/sse.html — real-time updates with SSE -->
<div hx-ext="sse" sse-connect="/events/articles">
  <div sse-swap="newArticle" hx-swap="afterbegin">
    <!-- New articles appear here in real-time -->
  </div>
</div>
# views.py — SSE endpoint
import json
from django.http import StreamingHttpResponse

def article_events(request):
    def event_stream():
        for article in listen_for_new_articles():
            html = render_to_string("partials/article_card.html", {"article": article})
            yield f"event: newArticle\ndata: {html}\n\n"
    return StreamingHttpResponse(event_stream(), content_type="text/event-stream")

WebSocket

<!-- templates/ws.html — WebSocket integration -->
<div hx-ext="ws" ws-connect="/ws/chat">
  <div id="messages"></div>
  <form ws-send>
    <input name="message" placeholder="Type a message..." />
    <button type="submit">Send</button>
  </form>
</div>

Boosting (Progressive Enhancement)

<!-- templates/boost.html — make regular links/forms use AJAX -->
<body hx-boost="true">
  <!-- All links and forms in this body now use AJAX -->
  <nav>
    <a href="/articles">Articles</a>  <!-- AJAX navigation -->
    <a href="/about">About</a>
  </nav>
  <main id="content">
    <!-- Content swapped here -->
  </main>
</body>

Key Patterns

  • Server returns HTML fragments, not JSON — this is hypermedia, not REST
  • Use hx-target to control where responses are inserted; hx-swap controls how
  • Use hx-trigger with modifiers (delay, throttle, changed, once) for precise control
  • Use hx-boost="true" on <body> for easy progressive enhancement of existing sites
  • Use hx-swap-oob for updating multiple page sections from a single response
  • Use hx-indicator for loading states — htmx manages the CSS class automatically
  • Use hx-push-url to update browser URL for back-button support

Use it

Copy one of these into your project. Installing also returns the manifest and these snippets.

yaml
targets:
  - https://api.opensmartroute.ai/api/v1/registry/terminalskills-skills-htmx/manifest   # or paste the manifest below

Manifest

An Open Capability Manifest: the router reads it to know what this does, what it costs and when to pick it.

terminalskills-skills-htmx.ocm.jsonjson
{
  "ocm": "1",
  "id": "terminalskills-skills-htmx",
  "kind": "skill",
  "name": "htmx",
  "description": "htmx gives you access to AJAX, CSS transitions, WebSockets, and Server-Sent Events directly in HTML using attributes. It enables dynamic web UIs without writing JavaScript by letting any element issue HTTP requests and swap content into the DOM.",
  "publisher": "terminalskills",
  "version": "1.0.0",
  "capabilities": {
    "domains": [
      "coding"
    ],
    "tags": [
      "skill-md",
      "html",
      "hypermedia",
      "ajax",
      "sse",
      "websocket",
      "no-javascript",
      "skills-sh"
    ],
    "languages": [
      "en"
    ]
  },
  "quality_prior": 0.6,
  "examples": [
    "htmx gives you access to AJAX, CSS transitions, WebSockets, and Server-Sent Events directly in HTML using attributes. It enables dynamic web UIs without writing JavaScript by letting any element issue HTTP requests and swap content into the DOM."
  ],
  "primary": false,
  "metadata": {
    "source": {
      "provider": "skills.sh",
      "repository": "https://github.com/terminalskills/skills",
      "path": "skills/htmx/SKILL.md",
      "ref": "HEAD",
      "url": "https://github.com/terminalskills/skills/blob/HEAD/skills/htmx/SKILL.md",
      "key": "terminalskills/skills/skills/htmx/SKILL.md"
    },
    "compatibility": "any web server, html",
    "license": "Apache-2.0"
  },
  "instructions": "# htmx\n\nhtmx extends HTML with attributes like `hx-get`, `hx-post`, `hx-swap`, and `hx-trigger` to make any element capable of issuing HTTP requests and updating the DOM. The server returns HTML fragments, not JSON.\n\n## Installation\n\n```html\n<!-- index.html — add htmx via CDN or npm -->\n<script src=\"https://unpkg.com/htmx.org@2.0.4\"></script>\n<!-- Or: npm install htmx.org -->\n```\n\n## Core Attributes\n\n```html\n<!-- templates/core-demo.html — fundamental htmx attributes -->\n\n<!-- GET request, replace inner HTML of target -->\n<button hx-get=\"/api/articles\" hx-target=\"#article-list\" hx-swap=\"innerH",
  "cost": {
    "context_tokens": 1676
  }
}

Fetch it by URL: GET /api/v1/registry/terminalskills-skills-htmx/manifest?version=1.0.0

Reviews

Star ratings from people who tried it. One review per account; edit yours any time.

No reviews yet. Install it, try it, and be the first to rate it.