xiaohongshu
xiaohongshu
maud-syntax-fundamentals
Compile-time HTML templating with Maud using the html! macro for type-safe markup generation. Covers syntax patterns including elements, attributes, classes, IDs, content splicing, toggles, control flow (if/match/for), and DOCTYPE. Use when generating HTML in Rust, creating templates, or building...
Full skill instructions
Compile-time HTML templating for Rust with type safety and zero runtime overhead
html! macroELEMENT[.CLASS][#ID][ ATTRIBUTES] { CONTENT }
Key Symbols:
{} = Container elements with content; = Void/self-closing elements() = Runtime value splicing (escaped)[] = Conditional attributes/classes (toggles)@ = Control flow (if, match, for, while, let)use maud::html;
html! {
h1 { "Hello, world!" }
p { "Paragraph text" }
div { span { "Nested content" } }
article {
h2 { "Title" }
p { "Content goes here" }
}
}
html! {
br;
hr;
input type="text" name="email";
img src="photo.jpg" alt="Description";
link rel="stylesheet" href="styles.css";
meta charset="UTF-8";
}
Important: Terminate with ; - renders as <br> not <br />
use maud::{html, DOCTYPE};
html! {
(DOCTYPE)
html lang="en" {
head {
meta charset="UTF-8";
title { "My Page" }
}
body {
h1 { "Content" }
}
}
}
html! {
div.container { }
div.row.justify-center { }
p.text-lg.font-bold { "Styled text" }
// Quoted for special characters (hyphens, numbers)
div."col-sm-2" { }
div."bg-blue-500" { }
}
html! {
div #main { } // ✅ Rust 2021+
section #content { }
article #"post-123" { } // Quoted for hyphens/numbers
}
// ❌ Error in Rust 2021+
// div#main { } // Missing space before #
html! {
#header { } // <div id="header">
.container { } // <div class="container">
.card.shadow { } // <div class="card shadow">
}
html! {
a href="https://example.com" title="Link" { "Click here" }
input type="text" placeholder="Enter name" name="username";
img src="photo.jpg" alt="Description" width="300";
}
html! {
input type="checkbox" checked;
input type="text" disabled;
option value="1" selected;
script src="app.js" defer;
video controls autoplay;
}
html! {
article data-id="12345" data-category="tech" {
h2 { "Article Title" }
}
button
aria-label="Close dialog"
aria-pressed="true"
role="button"
{
"Close"
}
}
html! {
tag-cloud { }
custom-widget data-id="123" {
"Custom content"
}
}
let name = "Alice";
let count = 42;
html! {
p { "Hello, " (name) "!" } // Hello, Alice!
p { "Count: " (count) } // Count: 42
}
Important: Values in () are automatically HTML-escaped
html! {
p {
"Result: "
({
let x = 10;
let y = 20;
x + y
})
}
// Outputs: Result: 30
}
let url = "https://example.com";
let id = "post-123";
html! {
a href=(url) { "Link" }
div id=(id) { "Content" }
}
let base_url = "https://example.com";
let path = "/page";
html! {
a href={ (base_url) (path) } { "Link" }
// Outputs: href="https://example.com/page"
}
let class_name = "active";
let element_id = "main-section";
html! {
// Class splicing (two equivalent forms)
div.(class_name) { "Content" }
div class=(class_name) { "Content" }
// ID splicing
section #(element_id) { "Content" }
}
use maud::PreEscaped;
html! {
div {
// Auto-escaped (safe)
p { "Hello <world>" } // Outputs: Hello <world>
// Raw HTML (dangerous - use with caution)
(PreEscaped("<strong>Bold text</strong>"))
}
}
Security Warning: Only use PreEscaped with trusted, sanitized content. Never use with user input.
let is_checked = true;
let is_disabled = false;
html! {
input type="checkbox" checked[is_checked];
button disabled[is_disabled] { "Submit" }
}
let is_active = true;
let has_error = false;
html! {
div.base-class[is_active].error[has_error] { }
// Renders: <div class="base-class active">
}
let maybe_title: Option<String> = Some("Tooltip".to_string());
let no_title: Option<String> = None;
html! {
button title=[maybe_title] { "Hover" }
// Renders: <button title="Tooltip">
button title=[no_title] { "No tooltip" }
// Renders: <button> (attribute completely omitted)
}
let logged_in = true;
html! {
@if logged_in {
p { "Welcome back!" }
} @else {
p { "Please log in" }
}
}
let user: Option<User> = Some(User { name: "Alice".to_string() });
html! {
@if let Some(user) = &user {
p { "Hello, " (user.name) }
} @else {
p { "Guest" }
}
}
enum Status { Active, Pending, Inactive }
let status = Status::Active;
html! {
@match status {
Status::Active => {
span.badge.green { "Active" }
}
Status::Pending => {
span.badge.yellow { "Pending" }
}
Status::Inactive => {
span.badge.gray { "Inactive" }
}
}
}
let items = vec!["Apple", "Banana", "Cherry"];
html! {
ul {
@for item in &items {
li { (item) }
}
}
}
html! {
ol {
@for (i, item) in items.iter().enumerate() {
li { (i + 1) ". " (item) }
}
}
}
let mut count = 0;
html! {
@while count < 5 {
p { "Count: " (count) }
({ count += 1; })
}
}
html! {
@let user_name = "Alice";
@let greeting = format!("Hello, {}", user_name);
h1 { (greeting) }
@for i in 0..3 {
@let doubled = i * 2;
p { (i) " × 2 = " (doubled) }
}
}
fn nav_link(href: &str, text: &str, is_current: bool) -> Markup {
html! {
a.nav-link[is_current] href=(href) { (text) }
}
}
fn form_field(name: &str, error: Option<&str>) -> Markup {
html! {
div.form-group {
input type="text" name=(name);
@if let Some(err) = error {
span.error { (err) }
}
}
}
}
fn render_list(items: &[String]) -> Markup {
html! {
ul {
@for item in items {
li { (item) }
}
}
}
}
Any type implementing Display can be spliced:
struct UserId(u64);
impl std::fmt::Display for UserId {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
let id = UserId(123);
html! {
p { "User ID: " (id) }
}
// ❌ Error
html! {
div#myid { }
}
// ✅ Correct
html! {
div #myid { }
}
// ❌ Wrong - outputs escaped HTML entities
html! {
{ "<b>Bold</b>" }
}
// Outputs: <b>Bold</b>
// ✅ Correct - renders as HTML
use maud::PreEscaped;
html! {
(PreEscaped("<b>Bold</b>"))
}
// Outputs: <b>Bold</b>
// ❌ May fail - compiler can't infer type
let items = vec![];
html! {
@for item in &items {
li { (item) }
}
}
// ✅ Correct - explicit type
let items: Vec<String> = vec![];
// ❌ Runtime template (Tera, Handlebars)
// template.html: <h1>{{ title }}</h1>
// context.insert("title", &title);
// tera.render("template.html", &context)?
// ✅ Compile-time template (Maud)
html! {
h1 { (title) }
}
use serde::Serialize;
#[derive(Serialize)]
struct Post {
id: u64,
title: String,
published: bool,
}
let post = Post {
id: 1,
title: "Hello".to_string(),
published: true,
};
html! {
article data-id=(post.id) {
h2 { (post.title) }
@if post.published {
span.badge { "Published" }
}
}
}
() for splicing, never PreEscaped with untrusted data@let for complex expressions - Improves readability@match over nested @if| Feature | Maud | Tera/Handlebars |
|---|---|---|
| Compile-time validation | ✅ Yes | ❌ No |
| Type safety | ✅ Yes | ❌ No |
| Runtime overhead | ✅ Minimal (~100 SLoC) | ❌ Large |
| Template hot-reload | ❌ No* | ✅ Yes |
| Learning curve | Medium | Easy |
| Binary size | ✅ Smallest | Larger |
*Can be achieved with shared library reloading in development
xiaohongshu
technical spec
product ux expert
database patterns
Conduct multi-agent task orchestration and workflow coordination.
Initialize project with Conductor artifacts (product definition,
Expert in web animations, transitions, and motion design using Framer Motion and CSS
Creates Mermaid and ASCII diagrams for flowcharts, architecture, ERDs, state machines, mindmaps, and more. Use when user mentions diagram, flowchart, mermaid, ASCII diagram, text diagram, terminal diagram, visualize, C4, mindmap, architecture diagram, sequence diagram, ERD, or needs visual docume...
PostgreSQL bindings for H3 hexagonal grid system. Use when working with H3 cells in Postgres, including spatial indexing, geometry/geography integration, and raster analysis.
Context-Driven Development skill for projects using Conductor. Use this skill when you detect a `conductor/` directory in the project, when working on tasks defined in a `plan.md` file, or when the user asks about tracks, specs, or plans. Automatically applies TDD workflow, tracks task completion...
Display project status, active tracks, and next actions
Official Stakpak application containerization standard operating procedure, a step-by-step guidline to properly dockerize applications. This is a rule book curated by the Stakpak Team.
Generate, edit, and beat-sync AI video with leading models in one workspace.
The world's fastest calendar for remote work
Transform Your Design with AI Designer by ImgCreator.ai
Revolutionizing Video Production with AI-Powered Creativity
Extend an image past the frame and let AI fill the new aspect ratio.
Discover your celebrity doppelgänger with StarByFace!
ChainClarity explains 700+ crypto whitepapers in plain English, with layered summaries, comparisons, research tools, alerts, and a $4.99 Pro plan.
Opus.ai: Revolutionize Your Web Experience