hyperion_html
Function-based HTML templates for Hypermedia-Driven Applications.
Build node trees with hyperion_html/tag and hyperion_html/node,
then render them to a string with to_html. Text and attribute values
are HTML-escaped (via houdini); use node.unsafe_raw_text for markup
you already trust.
One tree can be used to render the full page or fragments of it.
Declare the fragments with node.fragment, then render only some of them
by id by using with_only.
An optional typed context can be attached with with_context and read
at render time by node.lazy callbacks (or modified per-subtree with
node.scope).
Types
Render options for to_html.
pub type RenderOptions(ctx) {
RenderOptions(only: List(String), doctype: Bool, context: ctx)
}
Constructors
-
RenderOptions(only: List(String), doctype: Bool, context: ctx)with_only: which fragments to renderwith_doctype: whether to prepend a doctypewith_context: the context to use in this tree
Values
pub fn options() -> RenderOptions(Nil)
Default options: full render, no doctype, and Nil as the context.
pub fn to_html(
nodes nodes: List(node.Node(ctx)),
options options: RenderOptions(ctx),
) -> String
Render nodes to an HTML string.
The same tree renders in two modes:
- Full render (empty
onlylist): every node is rendered, fragments included. - Partial render (list of IDs given to
with_only): only the requested fragments are rendered.
Fragment callbacks are told which mode is being rendered (see
node.fragment). The context value is handed to node.lazy callbacks,
possibly updated along the way by node.scope.
Example
Renders "<p>Hello Quentin</p>" using an explicit parameter.
fn component_without_context(username: String) {
hyperion_html.to_html(
[tag.p([], [node.text("Hello " <> username)])],
hyperion_html.options(),
)
}
Renders "<p>Hello Quentin</p>" using a context.
In most cases you should favor using explicit parameters, as shown above,
since it makes the code clearer, but the context option can be useful to
avoid “prop drilling”, which refers to passing data through multiple layers
of components.
type SomeContext {
SomeContext(username: String)
}
fn component_with_context() {
let options =
hyperion_html.options()
|> hyperion_html.with_context(SomeContext(username: "Quentin"))
hyperion_html.to_html(
[
tag.p([], [
node.text("Hello "),
node.lazy(fn(c: SomeContext) { [text(c.username)] }),
]),
],
options,
)
}
pub fn with_context(
options: RenderOptions(ctx),
context: ctx,
) -> RenderOptions(ctx)
Attach a render-time context, read by node.lazy callbacks.
The context is any value — typically a record holding request-scoped
data such as the current user, a CSRF token or a locale. Because it is
typed, reading a field is compile-checked, unlike string-keyed lookup
tables. Trees that don’t read the context are polymorphic and work with
any context value; options() defaults it to Nil.
Use it when you want part of the tree to be built at render-time, or to read the context deep in a tree without having to pass it through every component.
Example
type Ctx {
Ctx(username: String)
}
hyperion_html.options()
|> hyperion_html.with_context(Ctx(username: "Quentin"))
|> hyperion_html.to_html(page, _)
pub fn with_doctype(
options: RenderOptions(ctx),
doctype: Bool,
) -> RenderOptions(ctx)
Prepend <!doctype html>\n to the output.
Use it when rendering a complete document.
pub fn with_only(
options: RenderOptions(ctx),
only: List(String),
) -> RenderOptions(ctx)
Render only the fragments whose IDs are in the list. An empty list (the default) renders the full page instead.