#html-template #html #template #macro

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

#200 in Template engine

Download history 1/week @ 2025-02-04 7/week @ 2025-02-25 2/week @ 2025-03-04 107/week @ 2025-04-22 47/week @ 2025-04-29

154 downloads per month

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

~320–780KB
~17K SLoC