Develop interactive web UIs using templ for type-safe components and HTMX for server-side dynamic content.
Install
mkdir -p .claude/skills/templ-htmx && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/2562" && unzip -o skill.zip -d .claude/skills/templ-htmx && rm skill.zipInstalls to .claude/skills/templ-htmx
Activation
This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.
Build interactive hypermedia-driven applications with templ and HTMX. Use when creating dynamic UIs, real-time updates, AJAX interactions, mentions 'HTMX', 'dynamic content', or 'interactive templ app'.Key capabilities
- →Mount HTMX in Go servers
- →Create type-safe templ components
- →Implement AJAX-like interactions
- →Handle real-time page updates
- →Use HTMX extensions like SSE and WebSockets
How it works
The skill integrates HTMX for client-side interactivity and templ for server-side rendering, allowing Go handlers to return HTML fragments based on HTMX requests.
Inputs & outputs
When to use templ-htmx
- →Create dynamic web components
- →Implement AJAX-like features in Go
- →Handle real-time page updates
- →Build interactive UIs without heavy JS
About this skill
Templ + HTMX Integration
Overview
HTMX enables modern, interactive web applications with minimal JavaScript. Combined with templ's type-safe components, you get fast, reliable hypermedia-driven UIs.
Key Benefits:
- No JavaScript framework needed
- Server-side rendering
- Minimal client-side code
- Progressive enhancement
- Type-safe components
When to Use This Skill
Use when:
- Building interactive UIs
- Creating dynamic content
- User mentions "HTMX", "dynamic updates", "real-time"
- Implementing AJAX-like behavior without JS
- Building SPAs without frameworks
Quick Start
1. Import and Mount HTMX
First, import the htmx package and mount it in your server:
import (
"within.website/x/htmx"
)
func main() {
mux := http.NewServeMux()
// Mount HTMX static files at /.within.website/x/htmx/
htmx.Mount(mux)
// ... other routes
}
2. Add HTMX to Layout
package components
import "within.website/x/htmx"
templ Layout(title string) {
<!DOCTYPE html>
<html>
<head>
<title>{ title }</title>
@htmx.Use()
</head>
<body>
{ children... }
</body>
</html>
}
The htmx.Use() component includes the core HTMX library. You can add extensions:
// Add SSE and path-params extensions
@htmx.Use("sse", "path-params")
Available extensions: event-header, path-params, remove-me, websocket.
3. Detect HTMX Requests
Use the htmx.Is() function to check if a request was made by HTMX:
import "within.website/x/htmx"
func handler(w http.ResponseWriter, r *http.Request) {
if htmx.Is(r) {
// Return partial HTML fragment for HTMX
components.Partial().Render(r.Context(), w)
} else {
// Return full page for direct navigation
components.FullPage().Render(r.Context(), w)
}
}
4. Create Interactive Component
templ Counter(count int) {
<div>
<p>Count: { strconv.Itoa(count) }</p>
<button
hx-post="/counter/increment"
hx-target="#counter"
hx-swap="outerHTML"
>
Increment
</button>
</div>
}
5. Create Handler
func incrementHandler(w http.ResponseWriter, r *http.Request) {
count := getCount() + 1
saveCount(count)
components.Counter(count).Render(r.Context(), w)
}
Core HTMX Attributes
hx-get / hx-post
Trigger HTTP requests:
templ SearchBox() {
<input
type="text"
name="q"
hx-get="/search"
hx-trigger="keyup changed delay:500ms"
hx-target="#results"
/>
<div id="results"></div>
}
Handler:
func searchHandler(w http.ResponseWriter, r *http.Request) {
query := r.URL.Query().Get("q")
results := search(query)
components.SearchResults(results).Render(r.Context(), w)
}
hx-target
Specify where to insert response:
templ LoadMore(page int) {
<button
hx-get={ "/posts?page=" + strconv.Itoa(page) }
hx-target="#posts"
hx-swap="beforeend"
>
Load More
</button>
}
hx-swap
Control how content is swapped:
// innerHTML (default)
hx-swap="innerHTML"
// outerHTML - replace element itself
hx-swap="outerHTML"
// beforeend - append inside
hx-swap="beforeend"
// afterend - insert after
hx-swap="afterend"
hx-trigger
Control when requests fire:
// On click (default for buttons)
<button hx-get="/data">Click me</button>
// On change
<select hx-get="/filter" hx-trigger="change">
// On keyup with delay
<input hx-get="/search" hx-trigger="keyup changed delay:300ms">
// On page load
<div hx-get="/data" hx-trigger="load">
// Every 5 seconds
<div hx-get="/updates" hx-trigger="every 5s">
Common Patterns
Pattern 1: Live Search
Component:
templ SearchBox() {
<div>
<input
type="text"
name="q"
placeholder="Search..."
hx-get="/search"
hx-trigger="keyup changed delay:500ms"
hx-target="#search-results"
hx-indicator="#spinner"
/>
<span id="spinner" class="htmx-indicator">
Searching...
</span>
</div>
<div id="search-results"></div>
}
templ SearchResults(results []string) {
<ul>
for _, result := range results {
<li>{ result }</li>
}
</ul>
}
Handler:
func searchHandler(w http.ResponseWriter, r *http.Request) {
query := r.URL.Query().Get("q")
results := performSearch(query)
components.SearchResults(results).Render(r.Context(), w)
}
Pattern 2: Infinite Scroll
templ PostList(posts []Post, page int) {
<div id="posts">
for _, post := range posts {
@PostCard(post)
}
</div>
if len(posts) > 0 {
<div
hx-get={ "/posts?page=" + strconv.Itoa(page+1) }
hx-trigger="revealed"
hx-swap="outerHTML"
>
Loading more...
</div>
}
}
Pattern 3: Delete with Confirmation
templ DeleteButton(itemID string) {
<button
hx-delete={ "/items/" + itemID }
hx-confirm="Are you sure?"
hx-target="closest tr"
hx-swap="outerHTML swap:1s"
>
Delete
</button>
}
Handler:
func deleteHandler(w http.ResponseWriter, r *http.Request) {
itemID := strings.TrimPrefix(r.URL.Path, "/items/")
deleteItem(itemID)
// Return empty to remove element
w.WriteHeader(http.StatusOK)
}
Pattern 4: Inline Edit
templ EditableField(id string, value string) {
<div id={ "field-" + id }>
<span>{ value }</span>
<button
hx-get={ "/edit/" + id }
hx-target={ "#field-" + id }
hx-swap="outerHTML"
>
Edit
</button>
</div>
}
templ EditForm(id string, value string) {
<form
hx-post={ "/save/" + id }
hx-target={ "#field-" + id }
hx-swap="outerHTML"
>
<input type="text" name="value" value={ value } />
<button type="submit">Save</button>
<button
hx-get={ "/cancel/" + id }
hx-target={ "#field-" + id }
>
Cancel
</button>
</form>
}
Pattern 5: Form Validation
templ SignupForm() {
<form hx-post="/signup" hx-target="#form-errors">
<div id="form-errors"></div>
<input
type="email"
name="email"
hx-post="/validate/email"
hx-trigger="blur"
hx-target="#email-error"
/>
<div id="email-error"></div>
<input type="password" name="password" />
<button type="submit">Sign Up</button>
</form>
}
templ ValidationError(message string) {
<span class="error">{ message }</span>
}
Pattern 6: Polling / Real-time Updates
templ LiveStats() {
<div
hx-get="/stats"
hx-trigger="load, every 5s"
hx-swap="innerHTML"
>
Loading stats...
</div>
}
templ StatsDisplay(stats Stats) {
<div>
<p>Users online: { strconv.Itoa(stats.UsersOnline) }</p>
<p>Active sessions: { strconv.Itoa(stats.Sessions) }</p>
</div>
}
Advanced Patterns
Out-of-Band Updates (OOB)
Update multiple parts of page:
templ CartButton(count int) {
<button id="cart-btn">
Cart ({ strconv.Itoa(count) })
</button>
}
templ AddToCartResponse(item Item) {
// Main response
<div class="notification">
Added { item.Name } to cart!
</div>
// Update cart button (different part of page)
<div id="cart-btn" hx-swap-oob="true">
@CartButton(getCartCount())
</div>
}
Progressive Enhancement
templ Form() {
<form
action="/submit"
method="POST"
hx-post="/submit"
hx-target="#result"
>
<input type="text" name="data" />
<button type="submit">Submit</button>
</form>
<div id="result"></div>
}
Works without JavaScript, enhanced with HTMX.
Loading States
templ DataTable() {
<div
hx-get="/data"
hx-trigger="load"
hx-indicator="#loading"
>
<div id="loading" class="htmx-indicator">
Loading data...
</div>
</div>
}
CSS:
.htmx-indicator {
display: none;
}
.htmx-request .htmx-indicator {
display: inline;
}
.htmx-request.htmx-indicator {
display: inline;
}
Response Headers
HX-Trigger
Trigger client-side events:
func handler(w http.ResponseWriter, r *http.Request) {
// Do work...
// Trigger custom event
w.Header().Set("HX-Trigger", "itemCreated")
components.Success().Render(r.Context(), w)
}
Client side:
document.body.addEventListener("itemCreated", function (evt) {
console.log("Item created!");
});
HX-Redirect
func handler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("HX-Redirect", "/dashboard")
w.WriteHeader(http.StatusOK)
}
HX-Refresh
func handler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("HX-Refresh", "true")
w.WriteHeader(http.StatusOK)
}
Special Status Code
Stop polling with status code 286:
import "within.website/x/htmx"
func pollHandler(w http.ResponseWriter, r *http.Request) {
if shouldStopPolling() {
w.WriteHeader(htmx.StatusStopPolling)
return
}
// ... return normal content
}
Request Headers
Access HTMX request headers:
import "within.website/x/htmx"
func handler(w http.ResponseWriter, r *http.Request) {
// Check if this is an HTMX request
if htmx.Is(r) {
// Get user's response to hx-prompt
promptResponse := r.Header.Get(htmx.HeaderPrompt)
}
}
Content truncated.
When not to use it
- →Building heavy client-side JavaScript frameworks
Prerequisites
Limitations
- →Requires Go-based backend
How it compares
It enables interactive web UIs using server-side hypermedia instead of building complex client-side JavaScript applications.
Compared to similar skills
templ-htmx side by side with the closest alternatives in the catalog.
| Skill | Installs | Updated | Safety | Difficulty |
|---|---|---|---|---|
| templ-htmx (this skill) | 3 | 7mo | No flags | Intermediate |
| ccxt-go | 1 | 6mo | Review | Intermediate |
| generating-grpc-services | 1 | 25d | Review | Advanced |
| higress-wasm-go-plugin | 1 | 6mo | Review | Advanced |
Try saying
Example prompts that trigger this skill in your AI assistant.
More by Xe
View all by Xe →You might also like
ccxt-go
ccxt
CCXT cryptocurrency exchange library for Go developers. Covers both REST API (standard) and WebSocket API (real-time). Helps install CCXT, connect to exchanges, fetch market data, place orders, stream live tickers/orderbooks, handle authentication, and manage errors in Go projects. Use when working with crypto exchanges in Go applications, microservices, or trading systems.
generating-grpc-services
jeremylongshore
Generate gRPC service definitions, stubs, and implementations from Protocol Buffers. Use when creating high-performance gRPC services. Trigger with phrases like "generate gRPC service", "create gRPC API", or "build gRPC server".
higress-wasm-go-plugin
alibaba
Develop Higress WASM plugins using Go 1.24+. Use when creating, modifying, or debugging Higress gateway plugins for HTTP request/response processing, external service calls, Redis integration, or custom gateway logic.
api-server
HoangNguyen0403
Standards for building HTTP services, REST APIs, and middleware in Golang.
API service
TheBearIsOne
Use this skill when: - adding HTTP endpoints; - defining request and response models; - wiring document generation into an API surface; - shaping controller, route, or handler behavior.
shadmin-dev
ahaodev
Apply Shadmin feature-development standards (backend Go/Gin/Ent + frontend React/TS). Use when adding/modifying features, CRUD modules, API routes/controllers/usecases/repositories, Ent schemas, frontend pages/routes, React components, TanStack hooks, or any full-stack work in this project. Trigger