Expand description
Rust-native HTML templates with compile-time optimization.
avosetta provides the asx! macro, a compact HTML templating syntax that
follows Rust’s expression and control-flow conventions. A template expands to
an opaque value implementing Html; render it by calling Html::write
with a String buffer.
The macro is designed to leave very little work for runtime. Adjacent static
output is combined into larger string writes, and HTML escaping for static
string literals is performed during compilation. Dynamic values are rendered
through Html.
§Example
use avosetta::{asx, Html};
let name = "<Ada>";
let page = asx! {
main[class="profile"] {
h1 { "Hello, " @name }
input[disabled=true];
}
};
let mut html = String::new();
page.write(&mut html);
assert_eq!(
html,
r#"<main class="profile"><h1>Hello, <Ada></h1><input disabled="disabled"></main>"#,
);§Syntax reference
§Elements
Write an element name followed by a braced child template:
div {
span { "content" }
}Void elements end with a semicolon instead of a child block:
meta[charset="utf-8"];
input[type="text", required=true];Names that are not Rust identifiers, including custom elements, can be string literals:
"x-user-card" {
div["x-data"="open"] { }
}Template formatting is not copied to the output. Add a string literal when whitespace is significant.
§Attributes
Attributes are written in square brackets after an element name. Separate entries with commas, and use string literals for names that cannot be written as Rust identifiers:
a[href=destination, class="button", "aria-label"=label] {
"Open"
}Attribute values are Rust expressions and are rendered through Html.
String values are escaped. Boolean and optional values are useful for
conditional attributes: false and None omit the attribute, while true
emits name="name".
§Text and interpolation
A string literal can appear directly in a template. It is escaped at compile time and becomes part of the macro’s static output:
p { "5 < 8 & 8 > 5" }Prefix a Rust expression with @ to interpolate it. The expression’s result
must implement Html:
p { "Welcome, " @user_name }
p { @format_args!("{} items", count) }Dynamic strings and characters are escaped at runtime. To insert trusted,
already-rendered markup without escaping, wrap it in Raw:
div { @Raw("<strong>trusted HTML</strong>") }Only use Raw for content whose origin and safety you control.
§Rust statements and control flow
@ also introduces Rust statements and control-flow forms. Their template
bodies use avosetta syntax, so interpolated Rust inside those bodies still
needs @:
@let heading = "Messages";
h1 { @heading }
@if messages.is_empty() {
p { "No messages" }
} else {
ul {
@for message in messages {
li { @message }
}
}
}match follows Rust’s arm syntax, but template-producing arms use braces. A
static string literal may be used directly as an arm body:
@match status {
Status::Ready => { strong { "Ready" } }
Status::Waiting => "Waiting",
}Local Rust items and statements may also be introduced with @. Values from
the surrounding scope can be referenced normally; the generated template
captures them with move semantics.
§Rendering values
Html is implemented for common text and numeric types, booleans,
Option, Result, formatting std::fmt::Arguments, slices, boxed
slices, and vectors. Collections render their items in order. None renders
nothing, and a Result renders whichever variant it contains.
Implement Html for application-specific renderable values, or compose
templates by returning the opaque Html value produced by asx!.
Macros§
- asx
- Builds an optimized HTML template using Rust-like syntax.
Structs§
- Attr
- Renders an HTML attribute from a key and value.
- Escape
- Escapes a string-like value for safe insertion into HTML text or an attribute value.
- Raw
- Marks a string-like value as trusted HTML and writes it without escaping.
Traits§
- Html
- A value that can append an HTML representation to a string buffer.