| Crates.io | htmxology |
| lib.rs | htmxology |
| version | 0.26.1 |
| created_at | 2024-11-12 13:18:54.695075+00 |
| updated_at | 2026-01-21 16:20:31.820672+00 |
| description | HTMX server-side rendering framework for Rust, based on Axum. |
| homepage | |
| repository | https://github.com/ereOn/htmxology.rs |
| max_upload_size | |
| id | 1444924 |
| size | 192,705 |
A type-safe, full-stack web framework for Rust that brings together the power of HTMX and Axum for server-side rendering.
HTMXOLOGY makes building interactive web applications with HTMX in Rust a joy. It provides:
Add HTMXOLOGY to your Cargo.toml:
[dependencies]
htmxology = { version = "0.18", features = ["full"] }
tokio = { version = "1", features = ["full"] }
Create a simple app:
use htmxology::{Route, Controller, Server};
// Define your routes as an enum
#[derive(Route)]
enum AppRoute {
#[route(GET, "/")]
Home,
#[route(GET, "/about")]
About,
#[route(GET, "/users/{id}")]
User(u32),
}
// Implement a controller
struct AppController;
#[htmxology::async_trait]
impl Controller for AppController {
type Route = AppRoute;
type Args = ();
type Response = Result<axum::response::Response, axum::response::Response>;
async fn handle_request(
&self,
route: AppRoute,
htmx: htmxology::htmx::Request,
parts: http::request::Parts,
server_info: &htmxology::ServerInfo,
) -> Self::Response {
match route {
AppRoute::Home => Ok(axum::response::Html("<h1>Home</h1>").into_response()),
AppRoute::About => Ok(axum::response::Html("<h1>About</h1>").into_response()),
AppRoute::User(id) => {
Ok(axum::response::Html(format!("<h1>User {}</h1>", id)).into_response())
}
}
}
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
Server::builder("127.0.0.1:3000")
.await?
.build()
.serve(AppController)
.await?;
Ok(())
}
Routes are defined as Rust enums, making your routing logic type-safe and refactor-friendly:
#[derive(Route)]
enum BlogRoute {
#[route(GET, "/")]
Index,
#[route(GET, "/posts/{id}")]
Post(u32),
#[route(POST, "/posts", body("application/x-www-form-urlencoded"))]
CreatePost(#[body] PostForm),
#[route(GET, "/search", query)]
Search(#[query] SearchQuery),
}
// Generate URLs with Display
let url = BlogRoute::Post(42).to_string(); // "/posts/42"
// Use in HTMX templates
let attr = BlogRoute::Search(query).as_htmx_attribute(); // hx-get="/search?q=..."
Build modular applications with nested controllers:
#[derive(RoutingController)]
#[controller(AppRoute)]
#[subcontroller(BlogController, route = Blog, path = "blog/")]
#[subcontroller(ApiController, route = Api, path = "api/")]
struct AppController {
blog: BlogController,
api: ApiController,
}
First-class support for HTMX features:
// Access HTMX headers
if htmx.is_htmx_request() {
// Return partial HTML
} else {
// Return full page
}
// Generate HTMX attributes from routes
BlogRoute::Post(42).as_htmx_attribute() // "hx-get=\"/posts/42\""
// Type-safe HTML IDs
let id = HtmlId::new("my-element");
Add caching to any controller:
use htmxology::{Cache, CachingControllerExt};
let cached_controller = my_controller.with_cache(Cache::default());
Integrate with Askama templates:
#[derive(Template)]
#[template(path = "index.html")]
struct IndexTemplate {
title: String,
items: Vec<Item>,
}
// Use RenderIntoResponse trait
impl Controller for MyController {
async fn handle_request(&self, ...) -> Self::Response {
let template = IndexTemplate { ... };
Ok(template.render_into_response()?)
}
}
derive - Enable derive macros (Route, DisplayDelegate, RoutingController)templating - Askama template integrationauto-reload - Development hot-reload supportinterfaces - Network interface detectionws - WebSocket supportfull - Enable all featuresCheck out the examples directory for complete applications:
blocks - Component-based UI with HTMXcomponents - Reusable component patternsRun an example:
cargo install just
just example blocks
Contributions are welcome! Please see CONTRIBUTING.md for details.
Licensed under the MIT License. See LICENSE-MIT for details.