A safe HTML DSL for Rust and WebAssembly
Build HTML in plain Rust.
Molt gives you a fluent builder and an html! macro, escapes everything once on entry, and renders a plain string. Zero dependencies, about 25 KB of WebAssembly, and a static site you can host anywhere.
cargo add molt-frameworkMIT licensed. Version 1.x, so what compiles today keeps compiling.
use molt::prelude::*;
fn main() {
let name = "<script>alert(1)</script>";
let card = div()
.add_class("card")
.child(h1().text("Hello, Molt"))
.child(p().text(name));
println!("{}", card.render());
// <div class="card"><h1>Hello, Molt</h1><p><script>alert(1)</script></p></div>
}
Safe by default, small by design
Template engines make you remember to escape. Runtimes make you ship kilobytes you never asked for. Molt does neither: it is only the HTML layer, and it plugs into the rest of your stack through a String.
Safe by construction
Text and attribute values are escaped once, where they enter. A javascript: URL is written as #. There is no way to forget.
Zero dependencies
cargo tree on the default features shows one crate: Molt. wasm-bindgen and rayon are opt-in.
Builder or macro
Use the fluent builder or the html! macro. The macro expands to the same builder calls, never to a second code path.
Static site generator included
Write pages and assets to disk, with sitemaps and RSS feeds. The output is plain HTML you can host anywhere.
Accessibility audit
Audit the tree before the page ships: images without alt text, buttons and links without a name, and more.
Calm under hostile input
A 100,000-level tree renders without crashing the process, and golden fixtures pin the output byte for byte, so a markup change is a failing test.
Fast enough that it is never the bottleneck
Numbers from the project's own benchmarks and test suite, measured on the development machine.
- ≈ 400 µsto render a 10,000-item list
Compact mode, measured with Criterion.
- ≈ 25 KBgzipped WebAssembly build
Opt in with the wasm feature.
- 0mandatory dependencies
The default build is one crate.
- forbidunsafe code
The crate sets unsafe_code to forbid.
Hosting is the easy part
Molt renders a string and the static site generator writes plain HTML. There is no server to run and nothing to keep warm. This very site is built with Molt.
- Run cargo run and get a dist folder of plain HTML.
- Push the project to GitHub.
- Let a static host publish it. This site uses AWS Amplify, which builds on every push.
The same core, in the browser
Build with wasm-pack and call Molt from JavaScript. Same renderer, same escaping rules, about 25 KB gzipped.
Read the WebAssembly guideBuild it, then call it from JavaScript.
$ cargo install wasm-pack
$ wasm-pack build --target web --features wasm
# writes pkg/molt.js and pkg/molt_bg.wasm
# serve the folder over HTTP, ES modules need it
$ python3 -m http.server
import init, { element, WDocument } from "./pkg/molt.js";
await init();
const page = new WDocument("en")
.addBody(element("h1").text("Hello, Molt"))
.addBody(element("p").text("Same renderer."));
document.body.innerHTML = page.render();
Your first page is one cargo add away
Follow the Getting Started guide, or browse the full API reference on docs.rs.