#macro #html #html-template

no-std vy

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

#221 in Template engine

Download history 44/week @ 2025-05-14 8/week @ 2025-05-21 50/week @ 2025-05-28 14/week @ 2025-06-04 34/week @ 2025-06-11 5/week @ 2025-06-18 22/week @ 2025-06-25 8/week @ 2025-07-02 38/week @ 2025-07-09 48/week @ 2025-07-16 14/week @ 2025-07-23 10/week @ 2025-07-30 29/week @ 2025-08-06 15/week @ 2025-08-13 29/week @ 2025-08-20 13/week @ 2025-08-27

86 downloads per month
Used in git-back

MIT license

40KB
928 lines

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

~295–740KB
~16K SLoC