Thanks to visit codestin.com
Credit goes to lib.rs

#html #markup #html-template

plait

A modern HTML templating library for Rust that embraces composition

1 unstable release

Uses new Rust 2024

new 0.1.0 Jan 22, 2026

#112 in Template engine

MIT/Apache

80KB
1.5K SLoC

plait

A fast, type-safe HTML templating library for Rust.

Plait provides compile-time HTML generation with a familiar, JSX-like syntax. Templates are checked at compile time and generate efficient code with minimal runtime overhead.

Quick Start

use plait::html;

let name = "World";
let output = html!(
    div class="greeting" {
        h1 { "Hello, " (name) "!" }
    }
);

assert_eq!(&*output, r#"<div class="greeting"><h1>Hello, World!</h1></div>"#);

Macros

Plait provides four main macros:

  • html! - Creates an Html value from a template
  • component! - Creates a reusable component that renders lazily
  • render! - Renders content to an existing HtmlFormatter
  • attrs! - Creates an Attributes collection

Template Syntax

Elements

Elements are written as name { children } for normal elements or name; for void elements:

use plait::html;

let output = html!(
    div {
        p { "A paragraph" }
        br;
        input type="text" name="field";
    }
);

assert_eq!(&*output, r#"<div><p>A paragraph</p><br><input type="text" name="field"></div>"#);

Attributes

Attributes support several value types:

use plait::html;

let class_name = "container";
let maybe_id: Option<&str> = Some("main");
let is_disabled = true;

let output = html!(
    div
        class="literal"              // Literal string
        data-value=(class_name)      // Dynamic expression
        id=[maybe_id]                // Optional (renders if Some)
        disabled?[is_disabled]       // Boolean (renders if true)
    {
        "content"
    }
);

assert_eq!(&*output, r#"<div class="literal" data-value="container" id="main" disabled>content</div>"#);

Dynamic Content

Expressions in parentheses are escaped by default:

use plait::html;

let user_input = "<script>alert('xss')</script>";

let output = html!(
    div { (user_input) }
);

// Content is safely escaped
assert!(!output.contains("<script>"));

Use : raw to include pre-escaped content:

use plait::html;

let trusted_html = "<strong>Bold</strong>";

let output = html!(
    div { (trusted_html : raw) }
);

assert!(output.contains("<strong>"));

Control Flow

Conditionals

use plait::html;

let show = true;
let value: Option<&str> = Some("hello");

let output = html!(
    div {
        @if show {
            span { "Visible" }
        }

        @if let Some(v) = value {
            span { (v) }
        } @else {
            span { "No value" }
        }
    }
);

assert_eq!(&*output, r#"<div><span>Visible</span><span>hello</span></div>"#);

Loops

use plait::html;

let items = vec!["one", "two", "three"];

let output = html!(
    ul {
        @for item in &items {
            li { (item) }
        }
    }
);

assert_eq!(&*output, r#"<ul><li>one</li><li>two</li><li>three</li></ul>"#);

Match Expressions

use plait::html;

enum Status { Active, Inactive }
let status = Status::Active;

let output = html!(
    span {
        @match status {
            Status::Active => "Online",
            Status::Inactive => "Offline",
        }
    }
);

assert_eq!(&*output, r#"<span>Online</span>"#);

Custom Components

Use the component! macro to create reusable components as functions:

use plait::{Render, component};

fn button(label: &str, primary: bool) -> impl Render + '_ {
    let class = if primary { "btn btn-primary" } else { "btn" };
    component! {
        button class=(class) { (label) }
    }
}

// Use in templates
let output = plait::html!(
    div { (button("Click me", true)) }
);

assert_eq!(&*output, r#"<div><button class="btn btn-primary">Click me</button></div>"#);

For components with owned data, use (&value) to borrow:

use plait::{Render, component};

fn greeting(message: String) -> impl Render {
    component! {
        span { (&message) }
    }
}

For more control, implement the Render trait directly. See the Render documentation for details.

Safety

Plait automatically escapes dynamic content to prevent XSS vulnerabilities. The Html and PreEscaped types represent content that is already safe and will not be escaped again.

License

Licensed under either of

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

Dependencies

~1.1–1.8MB
~35K SLoC