#macro #html-template #html

macro vy-macros

A convenient and type-safe HTML templating library

3 unstable releases

0.2.0 Apr 26, 2025
0.1.1 Oct 17, 2024
0.1.0 Oct 15, 2024

#102 in #html-template

Download history 37/week @ 2025-05-24 20/week @ 2025-05-31 13/week @ 2025-06-07 26/week @ 2025-06-14 18/week @ 2025-06-21 10/week @ 2025-06-28 12/week @ 2025-07-05 55/week @ 2025-07-12 19/week @ 2025-07-19 6/week @ 2025-07-26 8/week @ 2025-08-02 28/week @ 2025-08-09 21/week @ 2025-08-16 16/week @ 2025-08-23 22/week @ 2025-08-30 10/week @ 2025-09-06

73 downloads per month
Used in 2 crates (via vy)

MIT license

69KB
1.5K SLoC

vy

crates.io docs.rs build license: MIT

A convenient, type-safe HTML templating library for Rust

Usage

Create a typical HTML page:

use vy::prelude::*;

fn page(content: impl IntoHtml) -> impl IntoHtml {
    (
        DOCTYPE,
        html!(
            head!(
                meta!(charset = "UTF-8"),
                title!("My Title"),
                meta!(
                    name = "viewport",
                    content = "width=device-width,initial-scale=1"
                ),
                meta!(name = "description", content = ""),
                link!(rel = "icon", href = "favicon.ico")
            ),
            body!(
                h1!("My Heading"),
                content
            )
        ),
    )
}

Key features to note:

  • Tag macros: HTML elements are created using dedicated macros.
  • Inline attributes: Attributes are declared directly within macro bodies using key = value syntax.
  • Zero wrapping: No need for container macros – elements compose naturally.
  • Void element support: Automatically handles self-closing tags like <meta>, <img>, etc.

Syntax

The macro grammar follows this pattern:

element := [attribute],* [content],*

content := expression
attribute := name['?'] '=' expression
name := identifier | text

Key design choices

  • Parenthesis-based: Works with rustfmt formatting constraints.
  • Reserved word handling: Attributes like type and for use string syntax, e.g., "type" = ".." instead of type = "..".
  • Optional attributes: ? marks optional attributes (e.g., disabled? = Some("")).

Why this syntax?

The macro design balances several constraints:

  • Compatibility with Rust's syntax tree.
  • rustfmt compatibility (requires parenthesis syntax, e.g., div!() instead of div!{}).
  • Natural HTML-like authoring experience.
  • Compile-time validation.

Escaping

Escaping is done automatically, but can be opted out by wrapping a type with PreEscaped(..).

Performance

vy utilizes a few practices for fast rendering times:

  • Pre-calculated sizing: HTML output size is estimated before allocation.
  • Single-allocation rendering: Most templates render in one memory allocation.
  • Zero-cost composition: Macros expand to tuple-based IntoHtml types without closures.

Dependencies

~275–710KB
~15K SLoC