Expand description
A blazing fast type-checked HTML macro crate.
§Features
§Speed
The macros generate code that is as fast as writing HTML to a string by
hand, and intelligently combines what would be multiple push_str
calls
into one if there is no dynamic content between them.
The entire crate is #![no_std]
compatible, and allocation is completely
optional if you don’t use any dynamic content.
The crate gives extreme importance to lazy rendering and minimizing
allocation, so it will only render the HTML to a string when you finally
call Renderable::render
at the end. This makes composing nested HTML
elements extremely cheap.
§Type-Checking
All macro invocations are validated at compile time, so you can’t ever misspell an element/attribute or use invalid attributes.
It does this by looking in your current namespace, or a module named
hypertext_elements
(all the valid HTML elements are defined in this crate
already in hypertext_elements
, but it
doesn’t hard-code this module so you can define your own elements).
It then imports each element you use in your macro invocation, and then attempts to access the corresponding associated type for each attribute you use.
§Example
use hypertext::prelude::*;
maud! {
div #main title="Main Div" {
h1.important {
"Hello, world!"
}
@for i in 1..=3 {
p.{ "p-" (i) } {
"This is paragraph number " (i)
}
}
}
}
// expands to (roughly):
Lazy::<_, Node>::dangerously_create(move |buffer: &mut Buffer| {
const _: fn() = || {
use hypertext_elements::*;
fn check_element<K: ElementKind>(_: impl Element<Kind = K>) {}
check_element::<Normal>(h1);
let _: Attribute = <h1>::class;
check_element::<Normal>(p);
let _: Attribute = <p>::class;
check_element::<Normal>(div);
let _: Attribute = <div>::id;
let _: Attribute = <div>::title;
};
buffer
.dangerously_get_string()
.push_str(r#"<div id="main" title="Main Div">"#);
{
buffer
.dangerously_get_string()
.push_str(r#"<h1 class="important">Hello, world!</h1>"#);
for i in 1..=3 {
buffer.dangerously_get_string().push_str("<p class=\"p-");
i.render_to(buffer.as_attribute_buffer());
buffer
.dangerously_get_string()
.push_str(r#"">This is paragraph number "#);
i.render_to(buffer);
buffer.dangerously_get_string().push_str("</p>");
}
}
buffer.dangerously_get_string().push_str("</div>");
})
This approach is also extremely extensible, as you can define your own
traits to add attributes for your favourite libraries! In fact, this is
exactly what GlobalAttributes
does, and why it is required in the above
example, as it defines the attributes that can be used on any element, for
example id
, class
, and title
. This library comes with built-in
support for many popular frontend attribute-based frameworks in
validation::attributes
, such as HtmxAttributes
and
AlpineJsAttributes
Here’s an example of how you could define your own attributes for use with the wonderful frontend library htmx:
use hypertext::{
prelude::*,
validation::{Attribute, AttributeNamespace},
};
trait HtmxAttributes: GlobalAttributes {
const hx_get: Attribute = Attribute;
const hx_on: AttributeNamespace = AttributeNamespace;
// ...
}
impl<T: GlobalAttributes> HtmxAttributes for T {}
assert_eq!(
maud! {
div hx-get="/api/endpoint" hx-on:click="alert('Hello, world!')" {
// ^^^^^^ note that it converts `-` to `_` for you during checking!
"Hello, world!"
}
}
.render()
.as_inner(),
r#"<div hx-get="/api/endpoint" hx-on:click="alert('Hello, world!')">Hello, world!</div>"#,
);
Wrapping an attribue name in quotes will bypass the type-checking, so you can use any attribute you want, even if it doesn’t exist in the current context.
use hypertext::prelude::*;
assert_eq!(
maud! {
div "custom-attribute"="value" { "Hello, world!" }
}
.render()
.as_inner(),
r#"<div custom-attribute="value">Hello, world!</div>"#,
);
This library also supports component structs, which are simply structs that
implement Renderable
. If an element name is capitalized, it will be
treated as a component, with attributes representing the struct fields. The
#[component]
macro can be used to easily turn functions into
components.
use hypertext::{Buffer, prelude::*};
struct Repeater<R: Renderable> {
count: usize,
children: R,
}
impl<R: Renderable> Renderable for Repeater<R> {
fn render_to(&self, buffer: &mut Buffer) {
maud! {
@for i in 0..self.count {
(self.children)
}
}
.render_to(buffer);
}
}
assert_eq!(
maud! {
div {
Repeater count=3 {
// children are passed as a `Lazy` to the `children` field
p { "Hi!" }
}
}
}
.render()
.as_inner(),
"<div><p>Hi!</p><p>Hi!</p><p>Hi!</p></div>"
);
Modules§
- context
- The
Context
trait and its implementors. - prelude
- Re-exported items for convenience.
- validation
- Types and traits used for validation of HTML elements and attributes.
Macros§
- attribute
alloc
- Generate an attribute value, returning a
LazyAttribute
. - attribute_
borrow alloc
- Generate an attribute value, borrowing the environment.
- attribute_
static - Generate static HTML attributes.
- define_
elements - Define custom elements.
- define_
void_ elements - Define custom void elements.
- maud
alloc
- Generate HTML using
maud
syntax, returning aLazy
. - maud_
borrow alloc
- Generate HTML using
maud!
syntax, borrowing the environment. - maud_
static - Generate static HTML using
maud
syntax. - rsx
alloc
- Generate HTML using rsx syntax, returning a
Lazy
. - rsx_
borrow alloc
- Generate HTML using
rsx!
syntax, borrowing the environment. - rsx_
static - Generate static HTML using rsx syntax.
Structs§
- Buffer
alloc
- The buffer used for rendering HTML.
- Debugged
alloc
- A value rendered via its
Debug
implementation. - Displayed
alloc
- A value rendered via its
Display
implementation. - Lazy
alloc
- A value lazily rendered via a closure.
- Raw
- A raw pre-escaped string.
- Rendered
- A rendered HTML string.
Traits§
- Renderable
alloc
- A type that can be rendered as an HTML node.
- Renderable
Ext alloc
- An extension trait for
Renderable
types.
Type Aliases§
- Attribute
Buffer alloc
- A buffer used for rendering attribute values.
- Lazy
Attribute alloc
- An attribute value lazily rendered via a closure.
- RawAttribute
- A raw pre-escaped attribute value.
Attribute Macros§
- component
alloc
- Convert a function returning a
Renderable
into a component.
Derive Macros§
- Renderable
alloc
- Derive
Renderable
for a type.