### Expected Output of Basic Example
Source: https://maud.lambda.xyz/getting-started.html
The rendered HTML output from the basic Maud program.
```text
Hi, Lyra!
```
--------------------------------
### Basic Maud HTML Rendering Example
Source: https://maud.lambda.xyz/getting-started.html
A minimal Rust program demonstrating how to use the `maud::html!` macro to create and render an HTML string. The `html!` macro expands to a `Markup` type, which can be converted to a `String`.
```rust
use maud::html;
fn main() {
let name = "Lyra";
let markup = html! {
p { "Hi, " (name) "!" }
};
println!("{}", markup.into_string());
}
```
--------------------------------
### Render a Page Using Composed Markup
Source: https://maud.lambda.xyz/partials.html
Demonstrates how to use the `page` function to render the complete HTML structure, including dynamic content passed as Markup. This shows the practical application of the composed components.
```rust
page("Hello!", html! {
div { "Greetings, Maud." }
});
```
--------------------------------
### Create a New Rust Project
Source: https://maud.lambda.xyz/getting-started.html
Use Cargo to create a new binary Rust project. This sets up the basic project structure.
```bash
cargo new --bin pony-greeter
cd pony-greeter
```
--------------------------------
### Basic HTML Structure with Maud Macro
Source: https://maud.lambda.xyz/
This snippet demonstrates the basic syntax of the `html!` macro for creating HTML elements and text content. It shows how to define a heading and a paragraph with a link.
```rust
html! {
h1 { "Hello, world!" }
p.intro {
"This is an example of the "
a href="https://github.com/lambda-fairy/maud" { "Maud" }
" template language."
}
}
```
--------------------------------
### Using Classes and IDs
Source: https://maud.lambda.xyz/elements-attributes.html
Add classes and IDs using `.foo` and `#bar` syntax, which can be chained and mixed with other attributes. For Rust 2021 and later, `#` must be preceded by a space.
```rust
html! {
input #cannon .big.scary.bright-red type="button" value="Launch Party Cannon";
}
```
```rust
html! {
// Works on all Rust editions
input #pinkie;
// Works on Rust 2018 and older only
input#pinkie;
}
```
```rust
html! {
div."col-sm-2" { "Bootstrap column!" }
}
```
--------------------------------
### Define and Compose Header, Footer, and Page Markup
Source: https://maud.lambda.xyz/partials.html
Defines reusable header and footer components and a main page component that composes them. Use this pattern to build complex UIs from smaller, manageable parts.
```rust
use maud::{DOCTYPE, html, Markup};
/// A basic header with a dynamic `page_title`.
fn header(page_title: &str) -> Markup {
html! {
(DOCTYPE)
meta charset="utf-8";
title { (page_title) }
}
}
/// A static footer.
fn footer() -> Markup {
html! {
footer {
a href="rss.atom" { "RSS Feed" }
}
}
}
/// The final Markup, including `header` and `footer`.
///
/// Additionally takes a `greeting_box` that's `Markup`, not `&str`.
pub fn page(title: &str, greeting_box: Markup) -> Markup {
html! {
// Add the header markup to the page
(header(title))
h1 { (title) }
(greeting_box)
(footer())
}
}
```
--------------------------------
### Axum Integration with Maud
Source: https://maud.lambda.xyz/web-frameworks.html
Demonstrates returning Maud's `Markup` directly as a response in an Axum application. This utilizes the 'axum' feature for `IntoResponse` implementation.
```rust
use maud::{html, Markup};
use axum::{Router, routing::get};
async fn hello_world() -> Markup {
html! {
h1 { "Hello, World!" }
}
}
#[tokio::main]
async fn main() {
// build our application with a single route
let app = Router::new().route("/", get(hello_world));
// run it with hyper on localhost:3000
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
axum::serve(listener, app.into_make_service()).await.unwrap();
}
```
--------------------------------
### Rouille Integration with Maud
Source: https://maud.lambda.xyz/web-frameworks.html
Demonstrates how to directly use Maud's rendered HTML as a response in Rouille. No extra features are required.
```rust
use maud::html;
use rouille::{Response, router};
fn main() {
rouille::start_server("localhost:8000", move |request| {
router!(request,
(GET) (/{name: String}) => {
Response::html(html! {
h1 { "Hello, " (name) "!" }
p { "Nice to meet you!" }
})
},
_ => Response::empty_404()
)
});
}
```
--------------------------------
### Submillisecond Route Returning Maud Markup
Source: https://maud.lambda.xyz/web-frameworks.html
Shows how to define a Submillisecond route that returns Maud's HTML markup directly as a response.
```rust
use maud::{html, Markup};
use std::io::Result;
use submillisecond::{router, Application};
fn main() -> Result<()> {
Application::new(router! {
GET "/hello" => helloworld
})
.serve("0.0.0.0:3000")
}
fn helloworld() -> Markup {
html! {
h1 { "Hello, World!" }
}
}
```
--------------------------------
### Creating Elements with Content
Source: https://maud.lambda.xyz/elements-attributes.html
Use curly braces `{}` to define elements that contain other elements or text. This is the standard way to build nested HTML structures.
```rust
html! {
h1 { "Poem" }
p {
strong { "Rock," }
" you are a rock."
}
}
```
--------------------------------
### Shorthand for Including CSS Stylesheets
Source: https://maud.lambda.xyz/render-trait.html
Implement `Render` for a `Css` struct to create a shorthand for linking CSS stylesheets, reducing repetitive HTML.
```rust
use maud::{html, Markup, Render};
/// Links to a CSS stylesheet at the given path.
struct Css(&'static str);
impl Render for Css {
fn render(&self) -> Markup {
html! {
link rel="stylesheet" type="text/css" href=(self.0);
}
}
}
```
--------------------------------
### Tide Integration with Maud
Source: https://maud.lambda.xyz/web-frameworks.html
Illustrates using Maud's `html!` macro to generate responses directly within a Tide web application. Requires the 'tide' feature.
```rust
use maud::html;
use tide::Request;
use tide::prelude::*;
#[async_std::main]
async fn main() -> tide::Result<()> {
let mut app = tide::new();
app.at("/hello/:name").get(|req: Request<()>| async move {
let name: String = req.param("name")?.parse()?;
Ok(html! {
h1 { "Hello, " (name) "!" }
p { "Nice to meet you!" }
})
});
app.listen("127.0.0.1:8080").await?;
Ok(())
}
```
--------------------------------
### Actix Request Handler with Maud Markup
Source: https://maud.lambda.xyz/web-frameworks.html
Demonstrates an Actix request handler returning Maud's Markup, which implements actix_web::Responder.
```rust
use actix_web::{get, App, HttpServer, Result as AwResult};
use maud::{html, Markup};
use std::io;
#[get("/")]
async fn index() -> AwResult {
Ok(html! {
html {
body {
h1 { "Hello World!" }
}
}
})
}
#[actix_web::main]
async fn main() -> io::Result<()> {
HttpServer::new(|| App::new().service(index))
.bind(("127.0.0.1", 8080))?
.run()
.await
}
```
--------------------------------
### Warp Handler Returning Maud Markup
Source: https://maud.lambda.xyz/web-frameworks.html
Demonstrates a Warp handler that directly returns Maud's HTML markup as a warp::Reply.
```rust
use maud::html;
use warp::Filter;
#[tokio::main]
async fn main() {
let hello = warp::any().map(|| html! { h1 { "Hello, world!" } });
warp::serve(hello).run(([127, 0, 0, 1], 8000)).await;
}
```
--------------------------------
### Markdown Rendering with `pulldown-cmark` and `ammonia`
Source: https://maud.lambda.xyz/render-trait.html
Implement `Render` for a `Markdown` struct to convert Markdown text to sanitized HTML using `pulldown-cmark` for parsing and `ammonia` for security.
```rust
use ammonia;
use maud::{Markup, PreEscaped, Render};
use pulldown_cmark::{Parser, html};
/// Renders a block of Markdown using `pulldown-cmark`.
struct Markdown(T);
impl> Render for Markdown {
fn render(&self) -> Markup {
// Generate raw HTML
let mut unsafe_html = String::new();
let parser = Parser::new(self.0.as_ref());
html::push_html(&mut unsafe_html, parser);
// Sanitize it with ammonia
let safe_html = ammonia::clean(&unsafe_html);
PreEscaped(safe_html)
}
}
```
--------------------------------
### Add Maud Dependency to Cargo.toml
Source: https://maud.lambda.xyz/getting-started.html
Specify the Maud crate as a dependency in your project's Cargo.toml file. The asterisk (*) indicates the latest compatible version.
```toml
[dependencies]
maud = "*"
```
--------------------------------
### Add Actix-web Feature for Maud
Source: https://maud.lambda.xyz/web-frameworks.html
Include the 'actix-web' feature in your Cargo.toml to enable Maud integration with Actix.
```toml
# ...
[dependencies]
maud = { version = "*", features = ["actix-web"] }
# ...
```
--------------------------------
### Rocket Route Returning Maud Markup
Source: https://maud.lambda.xyz/web-frameworks.html
Shows a Rocket route handler that directly returns Maud's Markup, leveraging its Responder implementation.
```rust
use maud::{html, Markup};
use rocket::{get, routes};
use std::borrow::Cow;
#[get("/")]
fn hello(name: &str) -> Markup {
html! {
h1 { "Hello, " (name) "!" }
p { "Nice to meet you!" }
}
}
#[rocket::launch]
fn launch() -> _ {
rocket::build().mount("/", routes![hello])
}
```
--------------------------------
### Tide Feature for Maud
Source: https://maud.lambda.xyz/web-frameworks.html
Shows the Cargo.toml dependency for enabling Tide support in Maud. This allows returning Maud's HTML directly as a Tide response.
```toml
# ...
[dependencies]
maud = { version = "*", features = ["tide"] }
# ...
```
--------------------------------
### Poem Handler Returning Maud Markup
Source: https://maud.lambda.xyz/web-frameworks.html
Illustrates a Poem handler that returns Maud's HTML markup, which is automatically converted into a Poem response.
```rust
use maud::{html, Markup};
use poem::{get, handler, listener::TcpListener, Route, Server};
#[handler]
fn hello_world() -> Markup {
html! {
h1 { "Hello, World!" }
}
}
#[tokio::main]
async fn main() -> Result<(), std::io::Error> {
let app = Route::new().at("/hello", get(hello_world));
Server::new(TcpListener::bind("0.0.0.0:3000"))
.name("hello-world")
.run(app)
.await
}
```
--------------------------------
### Enable Submillisecond Feature for Maud
Source: https://maud.lambda.xyz/web-frameworks.html
Add the 'submillisecond' feature to your Maud dependency in Cargo.toml to enable Submillisecond integration.
```toml
# ...
[dependencies]
maud = { version = "*", features = ["submillisecond"] }
# ...
```
--------------------------------
### Enable Warp Feature for Maud
Source: https://maud.lambda.xyz/web-frameworks.html
Add the 'warp' feature to your Maud dependency in Cargo.toml to enable Warp integration.
```toml
# ...
[dependencies]
maud = { version = "*", features = ["warp"] }
# ...
```
--------------------------------
### Enable Poem Feature for Maud
Source: https://maud.lambda.xyz/web-frameworks.html
Add the 'poem' feature to your Maud dependency in Cargo.toml to enable Poem integration.
```toml
# ...
[dependencies]
maud = { version = "*", features = ["poem"] }
# ...
```
--------------------------------
### Pattern Matching with @match
Source: https://maud.lambda.xyz/control-structures.html
Implement exhaustive pattern matching using the @match construct, similar to Rust's match expressions. This allows for complex conditional logic based on enumerated types or other patterns.
```rust
enum Princess { Celestia, Luna, Cadance, TwilightSparkle }
let user = Princess::Celestia;
html! {
@match user {
Princess::Luna => {
h1 { "Super secret woona to-do list" }
ul {
li { "Nuke the Crystal Empire" }
li { "Kick a puppy" }
li { "Evil laugh" }
}
},
Princess::Celestia => {
p { "Sister, please stop reading my diary. It's rude." }
},
_ => p { "Nothing to see here; move along." }
}
}
```
--------------------------------
### Looping with @for
Source: https://maud.lambda.xyz/control-structures.html
Iterate over elements of an iterator using the @for .. in .. syntax. This is suitable for rendering lists or collections dynamically.
```rust
let names = ["Applejack", "Rarity", "Fluttershy"];
html! {
p { "My favorite ponies are:" }
ol {
@for name in &names {
li { (name) }
}
}
}
```
--------------------------------
### Axum Feature for Maud
Source: https://maud.lambda.xyz/web-frameworks.html
Shows the Cargo.toml dependency for enabling Axum support in Maud. This allows Maud's output to be used directly with Axum's `IntoResponse` trait.
```toml
# ...
[dependencies]
maud = { version = "*", features = ["axum"] }
# ...
```
--------------------------------
### Adding Non-Empty Attributes
Source: https://maud.lambda.xyz/elements-attributes.html
Attach attributes to elements using the `attr="value"` syntax. Attribute values must be quoted string literals.
```rust
html! {
ul {
li {
a href="about:blank" { "Apple Bloom" }
}
li class="lower-middle" {
"Sweetie Belle"
}
li dir="rtl" {
"Scootaloo "
small { "(also a chicken)" }
}
}
}
```
--------------------------------
### Defining Void Elements
Source: https://maud.lambda.xyz/elements-attributes.html
Terminate void elements, such as `
`, using a semicolon `;`. This ensures they are rendered correctly in HTML.
```rust
html! {
link rel="stylesheet" href="poetry.css";
p {
"Rock, you are a rock."
br;
"Gray, you are gray,"
br;
"Like a rock, which you are."
br;
"Rock."
}
}
```
--------------------------------
### Wrapper for `std::fmt::Debug` Rendering
Source: https://maud.lambda.xyz/render-trait.html
Use a `Debug` wrapper struct that implements `Render` to display internal state using the `Debug` trait when `Display` is not available. Overrides `.render_to()` for efficiency and uses `Escaper` to prevent XSS vulnerabilities.
```rust
use maud::{Escaper, html, Render};
use std::fmt;
use std::fmt::Write as _;
/// Renders the given value using its `Debug` implementation.
struct Debug(T);
impl Render for Debug {
fn render_to(&self, output: &mut String) {
let mut escaper = Escaper::new(output);
write!(escaper, "{{:?}}", self.0).unwrap();
}
}
```
--------------------------------
### Using DOCTYPE Constant for HTML Declaration
Source: https://maud.lambda.xyz/text-escaping.html
Insert a `` declaration using the `maud::DOCTYPE` constant for standard HTML5 document type.
```rust
use maud::DOCTYPE;
html! {
(DOCTYPE) //
}
```
--------------------------------
### Conditional Branching with @if, @else if, and @else
Source: https://maud.lambda.xyz/control-structures.html
Use @if, @else if, and @else for conditional rendering based on boolean expressions. Braces are mandatory, and the @else clause is optional. This mirrors Rust's if-else if-else syntax.
```rust
#[derive(PartialEq)]
enum Princess { Celestia, Luna, Cadance, TwilightSparkle }
let user = Princess::Celestia;
html! {
@if user == Princess::Luna {
h1 { "Super secret woona to-do list" }
ul {
li { "Nuke the Crystal Empire" }
li { "Kick a puppy" }
li { "Evil laugh" }
}
} @else if user == Princess::Celestia {
p { "Sister, please stop reading my diary. It's rude." }
} @else {
p { "Nothing to see here; move along." }
}
}
```
--------------------------------
### Basic Splice Usage
Source: https://maud.lambda.xyz/splices-toggles.html
Insert dynamic string values and computed values into HTML elements. HTML special characters are escaped by default.
```rust
let best_pony = "Pinkie Pie";
let numbers = [1, 2, 3, 4];
html! {
p { "Hi, " (best_pony) "!" }
p {
"I have " (numbers.len()) " numbers, "
"and the first one is " (numbers[0])
}
}
```
--------------------------------
### Toggle Classes
Source: https://maud.lambda.xyz/splices-toggles.html
Conditionally apply CSS classes to HTML elements based on a Rust boolean expression. The class is added only if the expression evaluates to true.
```rust
let cuteness = 95;
html! {
p.cute[cuteness > 50] { "Squee!" }
}
```
--------------------------------
### Variable Declaration with @let in Loops
Source: https://maud.lambda.xyz/control-structures.html
Declare new variables within a template scope using @let. This is particularly useful inside @for loops for intermediate calculations or transformations.
```rust
let names = ["Applejack", "Rarity", "Fluttershy"];
html! {
@for name in &names {
@let first_letter = name.chars().next().unwrap();
p {
"The first letter of "
b { (name) }
" is "
b { (first_letter) }
"."
}
}
}
```
--------------------------------
### Splices in Classes and IDs
Source: https://maud.lambda.xyz/splices-toggles.html
Dynamically set HTML element classes and IDs using splices. This allows for conditional styling or element identification.
```rust
let name = "rarity";
let severity = "critical";
html! {
aside #(name) {
p.{ "color-" (severity) } { "This is the worst! Possible! Thing!" }
}
}
```
--------------------------------
### Add Rocket Feature for Maud
Source: https://maud.lambda.xyz/web-frameworks.html
Include the 'rocket' feature in your Cargo.toml to enable Maud integration with Rocket.
```toml
# ...
[dependencies]
maud = { version = "*", features = ["rocket"] }
# ...
```
--------------------------------
### Optional Attributes with Values
Source: https://maud.lambda.xyz/splices-toggles.html
Render optional attributes using `attr=[Some(value)]` syntax. The attribute is rendered only if the value is `Some(T)`, and omitted if it's `None`.
```rust
html! {
p title=[Some("Good password")] { "Correct horse" }
@let value = Some(42);
input value=[value];
@let title: Option<&str> = None;
p title=[title] { "Battery staple" }
}
```
--------------------------------
### Raw String for Long or Special Character Content
Source: https://maud.lambda.xyz/text-escaping.html
Employ raw strings (prefixed with `r#"`) for lengthy strings or those with numerous special characters to avoid manual escaping.
```rust
html! {
pre {
r#"
Rocks, these are my rocks.
Sediments make me sedimental.
Smooth and round,
Asleep in the ground.
Shades of brown
And gray.
"#
}
}
```
--------------------------------
### Splicing Pre-Escaped Content
Source: https://maud.lambda.xyz/splices-toggles.html
Use the `PreEscaped` wrapper to insert HTML content directly without escaping. This is useful for rendering pre-formatted HTML strings.
```rust
use maud::PreEscaped;
let post = "Pre-escaped
";
html! {
h1 { "My super duper blog post" }
(PreEscaped(post))
}
```
--------------------------------
### Declaring Empty Attributes
Source: https://maud.lambda.xyz/elements-attributes.html
Declare an empty attribute by omitting its value. Previously, a `?` suffix was required, but this is no longer necessary for new code.
```rust
html! {
form {
input type="checkbox" name="cupcakes" checked;
" "
label for="cupcakes" { "Do you like cupcakes?" }
}
}
```
--------------------------------
### Conditional Let Binding with @if let
Source: https://maud.lambda.xyz/control-structures.html
Supports @if let for handling optional values or pattern matching within conditional blocks. The @else clause provides a fallback when the pattern does not match.
```rust
let user = Some("Pinkie Pie");
html! {
p {
"Hello, "
@if let Some(name) = user {
(name)
} @else {
"stranger"
}
"!"
}
}
```
--------------------------------
### Custom Elements and Data Attributes
Source: https://maud.lambda.xyz/elements-attributes.html
Maud supports elements and attributes with hyphens, including custom elements, data attributes (e.g., `data-index`), and ARIA annotations.
```rust
html! {
article data-index="12345" {
h1 { "My blog" }
tag-cloud { "pinkie pie pony cute" }
}
}
```
--------------------------------
### Concatenating Values in Attributes
Source: https://maud.lambda.xyz/splices-toggles.html
Wrap multiple values in braces within an attribute to concatenate them. This is useful for constructing URLs or complex attribute values.
```rust
const GITHUB: &'static str = "https://github.com";
html! {
a href={ (GITHUB) "/lambda-fairy/maud" } {
"Fork me on GitHub"
}
}
```
--------------------------------
### Toggle Boolean Attributes
Source: https://maud.lambda.xyz/splices-toggles.html
Conditionally render boolean HTML attributes based on a Rust boolean expression. The attribute is added only if the expression evaluates to true.
```rust
let allow_editing = true;
html! {
p contenteditable[allow_editing] {
"Edit me, I "
em { "dare" }
" you."
}
}
```
--------------------------------
### Literal String in Maud
Source: https://maud.lambda.xyz/text-escaping.html
Use double quotes for literal strings in Maud, similar to Rust. Backslashes are used for escape sequences.
```rust
html! {
"Oatmeal, are you crazy?"
}
```
--------------------------------
### Implicit Div Elements
Source: https://maud.lambda.xyz/elements-attributes.html
If an element name is omitted but a class or ID is provided, Maud assumes it is a `div` element.
```rust
html! {
#main {
"Main content!"
.tip { "Storing food in a refrigerator can make it 20% cooler." }
}
}
```
--------------------------------
### Splice with Arbitrary Rust Code
Source: https://maud.lambda.xyz/splices-toggles.html
Use Rust code blocks within splices for complex expressions that are difficult to read inline. Ensure the code block returns a value that implements the `Render` trait.
```rust
html! {
p {
({
let f: Foo = something_convertible_to_foo()?;
f.time().format("%H%Mh")
})
}
}
```
--------------------------------
### Splice in HTML Attributes
Source: https://maud.lambda.xyz/splices-toggles.html
Insert dynamic string values into HTML attributes. The value is automatically escaped.
```rust
let secret_message = "Surprise!";
html! {
p title=(secret_message) {
"Nothing to see here, move along."
}
}
```
--------------------------------
### Disabling HTML Escaping with PreEscaped
Source: https://maud.lambda.xyz/text-escaping.html
Wrap strings in `PreEscaped()` to prevent Maud from automatically escaping HTML special characters. This is useful for including raw HTML or script content.
```rust
use maud::PreEscaped;
html! {
"" // <script>...
(PreEscaped("")) //