name: rust-maud description: Write HTML in Rust using Maud — compile-time verified html! macro, component patterns, PreEscaped, Render trait, integration with Axum/Actix. license: MIT
rust-maud skill
What I do
Guide Maud template engine usage in Rust. Maud compiles templates to Rust code at compile time.
Quick Start
use maud::html;
let name = "World";
let markup = html! {
h1 { "Hello, " (name) "!" }
};
[dependencies]
maud = "*"
Syntax
Text and Escaping
html! { "Oatmeal, are you crazy?" } // Literal text
html! { pre { r#"Rocks, these are my rocks."# } } // Raw strings
html! { (PreEscaped("<script>")) } // Disable escaping
html! { (DOCTYPE) } // DOCTYPE
Elements
html! {
h1 { "Title" }
p { strong { "Bold" } " and normal" }
br; // Void elements end with ;
img src="img.png";
input type="text" name="user";
input type="checkbox" checked; // Boolean attribute
}
Classes and IDs
html! {
div#container.main-class {
"Content"
}
#main { "Main" } // Implicit div
.tip { "Tip" }
}
Splices (Values)
html! {
p { "Hi, " (name) "!" }
a href=(href) { "Link" }
a href={ (base) "/users" } { "API" } // Concatenate
div.#(theme)-theme { "Content" } // Splice in class
}
Toggles
html! {
div contenteditable[editable] { "Edit" }
li.active[is_active] { "Active" }
p title=[title] { "Optional attr" } // Option<T>
}
Control Flow
// @if / @else
@if user_logged_in {
a href="/logout" { "Logout" }
} @else {
a href="/login" { "Login" }
}
// @if let
@if let Some(name) = username {
p { "Welcome, " (name) }
}
// @for loop
@for item in &items {
li { (item) }
}
// @let
@let first = user.name.chars().next();
li { (first) ". " (user.name) }
// @match
@match status {
Status::Active => { span.active { "Active" } },
_ => { span { "Unknown" } }
}
Partials (Composition)
fn header(title: &str) -> Markup {
html! { head { title { (title) } } }
}
fn page(title: &str, content: Markup) -> Markup {
html! {
(header(title))
main { (content) }
}
}
Render Trait
use maud::{html, Render};
struct Button { label: &'static str, href: &'static str }
impl Render for Button {
fn render(&self) -> Markup {
html! { a href=(self.href) class="button" { (self.label) } }
}
}
html! { (Button { label: "Click", href: "/click" }) }
Framework Integration
// Actix-web
#[get("/")]
async fn index() -> Markup { html! { h1 { "Hello!" } } }
// Rocket
#[get("/<name>")]
fn hello(name: &str) -> Markup { html! { h1 { "Hello, " (name) "!" } } }
// Axum
async fn hello() -> Markup { html! { h1 { "Hello!" } } }
let app = Router::new().route("/", get(hello));
Best Practices
- Prefer functions for partials
- Implement
Renderfor domain types - Use toggles
[is_active]over@if - Push logic to Rust, not templates
- Use
PreEscapedsparingly
Use this skill when building Rust web apps with Maud templates.