> 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 HTTP requests and swap content into the DOM.

fetch
$curl "https://skillshub.wtf/TerminalSkills/skills/htmx?format=md"
SKILL.mdhtmx

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

> related_skills --same-repo

> zustand

You are an expert in Zustand, the small, fast, and scalable state management library for React. You help developers manage global state without boilerplate using Zustand's hook-based stores, selectors for performance, middleware (persist, devtools, immer), computed values, and async actions — replacing Redux complexity with a simple, un-opinionated API in under 1KB.

> zoho

Integrate and automate Zoho products. Use when a user asks to work with Zoho CRM, Zoho Books, Zoho Desk, Zoho Projects, Zoho Mail, or Zoho Creator, build custom integrations via Zoho APIs, automate workflows with Deluge scripting, sync data between Zoho apps and external systems, manage leads and deals, automate invoicing, build custom Zoho Creator apps, set up webhooks, or manage Zoho organization settings. Covers Zoho CRM, Books, Desk, Projects, Creator, and cross-product integrations.

> zod

You are an expert in Zod, the TypeScript-first schema declaration and validation library. You help developers define schemas that validate data at runtime AND infer TypeScript types at compile time — eliminating the need to write types and validators separately. Used for API input validation, form validation, environment variables, config files, and any data boundary.

> zipkin

Deploy and configure Zipkin for distributed tracing and request flow visualization. Use when a user needs to set up trace collection, instrument Java/Spring or other services with Zipkin, analyze service dependencies, or configure storage backends for trace data.

┌ stats

installs/wk0
░░░░░░░░░░
github stars17
███░░░░░░░
first seenMar 17, 2026
└────────────

┌ repo

TerminalSkills/skills
by TerminalSkills
└────────────

┌ tags

└────────────