rust_html
A HTML templating library for reusable components in web applications
About
rust_html is a tiny templating library that let's you easily create reusable HTML templates and components:
use ;
let card_component = ;
let title = "My Website";
let my_template: Template = rhtml! ;
let html_string: String = my_template.into;
println!;
Why use rust_html?
- Valid HTML syntax is enforced at compile-time
- Runtime rust values are automatically escaped to protect against injection attacks
- You can inject any expression or literal (not just identifiers)
The library is designed for creating reusable components for SSR
(server-side rendering), and is particularly nice in combination with front end libraries
like alpine.js
or htmx
. Unlike some other templating libraries, you can use the
standard HTML syntax directly and keep the templates next to your other Rust code.
Installation
Install from crates.io using cargo:
Usage
Types
The library has only 5 exported functions/types:
rhtml!
: The main macro for creating templatesTemplate
: represents a reusable HTML templateRender
: trait for implementing reusablestruct
componentsUnescaped
: string wrapper for inserting unescaped valuesTemplateGroup
: wrapper to insert aVec<Template>
[!NOTE]
TheTemplate
struct itself does not implement theDisplay
trait. To print or return the HTML value as aString
you can useString::from(my_template)
or justmy_template.into()
where applicable.
The rhtml!
macro
The rhtml!
macro accepts a single string literal as input, typically
"my text here"
or r#"my text here"#
which is a bit more convenient for HTML.
The macro returns a Template
struct that ensures injection safety when
reusing template within templates.
Inside the macro string you can inject anything that implements either the
std::fmt::Display
or Render
trait by using brackets {}
.
You can escape brackets inside the HTML by using two of them in a row ({{
or }}
).
Example - Reusable Components
use ;
/// Reusable card component with a title property
/// Reusable card group component that creates N cards
// Server endpoint
The your_endpoint
function will return the following HTML:
Card 0
Card 1
Card 2
Expressions inside a template
In some cases you might want to include simple logic in your template directly. You can use any valid Rust expression inside the macro:
use rhtml;
To prevent ambiguity you must only use {
and }
for opening/closing scopes
in the injected rust code - not inside literals or comments.
The following is therefore not valid:
rhtml! ;
// ^
// Bracket not allowed
Structs as reusable components
You can also use structs as components by implementing the Render
trait.
use ;
// Implement rust_html rendering for our component
Escaping
Template input is escaped by default to prevent injection attacks, for instance if
a user were to register with a name that contains a <script>
tag.
The following snippet:
let sketchy_user_input = "<script>alert('hi')</script>";
let page = rhtml! ;
println!;
Generates a string where dangerous characters are escaped:
<script>alert('hi')</script>
Unescaping
If you need the unescaped value, you can use the Unescaped
wrapper.
[!CAUTION]
Never useUnescaped
on untrusted user input or if you don't know what you're doing.
use ;
let sketchy_user_input = "<script>alert('hi')</script>";
let unescaped = Unescaped;
let page = rhtml! ;
println!;
...which results in this string:
Integration with web frameworks
Integrating with any web framework is trivial - simply convert the
template string to the response type for the given framework.
If you're using Axum you can add the axum
feature to get support
for their IntoResponse
trait.
Related projects
- maud: rust syntax for HTML
- askama: jinja like templating library
- tera: jinja2 like templating library
- handlebars-rust: handlebars templating language for rust
Look at the AWWY website for more examples.
Contributing
Run tests:
Run doc tests: