---
name: htmx-rust
description: Build interactive hypermedia-driven applications with Axum and HTMX. Use when creating dynamic UIs, real-time updates, AJAX interactions, mentions 'HTMX', 'dynamic content', or 'interactive web app'.
---
# HTMX + Axum Integration (Rust)
## Overview
HTMX enables modern, interactive web applications with minimal JavaScript. Combined with Rust's type safety and Axum's powerful routing, you get fast, reliable hypermedia-driven UIs with compile-time guarantees.
**Key Benefits:**
- No JavaScript framework needed
- Server-side rendering with Askama templates
- Type-safe request/response handling with Axum extractors
- Minimal client-side code
- Progressive enhancement
- Memory safety and zero-cost abstractions
## When to Use This Skill
Use when:
- Building interactive UIs with server-side rendering
- Creating dynamic content updates
- User mentions "HTMX", "dynamic updates", "real-time"
- Implementing AJAX-like behavior without JS
- Building interactive web apps without SPAs
## Quick Start
### 1. Add Dependencies
```toml
[dependencies]
axum = "0.7"
tokio = { version = "1", features = ["full"] }
askama = "0.12"
serde = { version = "1.0", features = ["derive"] }
```
### 2. Create Base Template (Askama)
```html
{{ title }}
{{ content }}
```
### 3. Create Interactive Component
```html
{# counter.html #}
Count: {{ count }}
```
Define the template struct:
```rust
use askama::Template;
#[derive(Template)]
#[template(path = "counter.html")]
struct CounterTemplate {
count: i32,
}
```
### 4. Create Handler
```rust
use axum::{
extract::{State},
response::IntoResponse,
Json,
};
async fn increment_counter(
State(state): State,
) -> impl IntoResponse {
let mut count = state.counter.lock().unwrap();
*count += 1;
CounterTemplate { count: *count }
}
```
### 5. Setup Router
```rust
use axum::{routing::post, Router};
#[tokio::main]
async fn main() {
let app = Router::new()
.route("/counter/increment", post(increment_counter))
.with_state(AppState::default());
let listener = tokio::net::TcpListener::bind("127.0.0.1:3000")
.await
.unwrap();
axum::serve(listener, app).await.unwrap();
}
```
---
## Core HTMX Attributes
### hx-get / hx-post
Trigger HTTP requests with Axum extractors:
```html
{# search.html #}
```
Handler with type-safe query parameters:
```rust
use axum::extract::Query;
use serde::Deserialize;
#[derive(Deserialize)]
struct SearchQuery {
q: String,
}
#[derive(Template)]
#[template(path = "search_results.html")]
struct SearchResults {
results: Vec,
}
async fn search(Query(params): Query) -> impl IntoResponse {
let results = perform_search(¶ms.q);
SearchResults { results }
}
```
### hx-target
Specify where to insert response:
```html
{# load_more.html #}
```
### hx-swap
Control how content is swapped:
```html
{# swap options #}
hx-swap="innerHTML"
hx-swap="outerHTML"
hx-swap="beforeend"
hx-swap="afterend"
```
### hx-trigger
Control when requests fire:
```html