lustre/element
Lustre wouldn’t be much use as a frontend framework if it didn’t provide a way to create HTML elements. This module contains the basic functions necessary to construct and manipulate different HTML elements.
It is also possible to use Lustre as a HTML templating library, without using its runtime or framework features.
Types
The Element
type is how Lustre represents chunks of HTML. The msg
type
variable is used to represent the types of messages that can be produced from
events on the element or its children.
Note: Just because an element can produces messages of a given type,
doesn’t mean that it will! The msg
type variable is used to represent the
potential for messages to be produced, not a guarantee.
The most basic ways to create elements are:
-
The
element
function to construct arbitrary HTML elements. You can also use this render Custom Elements (like those registered as Lustre components). -
The
text
function to turn a Gleam string into a text node. -
The
none
function to render nothing - useful for conditional rendering.
If you have more complex needs, there are two more-advanced functions:
-
The
namespaced
function to create elements in a specific XML namespace. This is useful for SVG or MathML elements, for example. -
The
advanced
function to create elements with more control over how the element is rendered when converted to a string. This is necessary because some HTML, SVG, and MathML elements are self-closing or void elements, and Lustre needs to know how to render them correctly!
For most applications, you’ll only need to use the simpler functions; usually
the text
and none
functions are enough. This is because
Lustre already provides a module with all the standard HTML and SVG elements
ready to use in lustre/element/html
and
lustre/element/svg
.
pub type Element(msg) =
vdom.Element(msg)
Functions
pub fn advanced(
namespace: String,
tag: String,
attrs: List(Attribute(a)),
children: List(Element(a)),
self_closing: Bool,
void: Bool,
) -> Element(a)
A function for constructing elements with more control over how the element is rendered when converted to a string. This is necessary because some HTML, SVG, and MathML elements are self-closing or void elements, and Lustre needs to know how to render them correctly!
pub fn element(
tag: String,
attrs: List(Attribute(a)),
children: List(Element(a)),
) -> Element(a)
A general function for constructing any kind of element. In most cases you
will want to use the lustre/element/html
instead but this
function is particularly handy when constructing custom elements, either
from your own Lustre components or from external JavaScript libraries.
Note: Because Lustre is primarily used to create HTML, this function special-cases the following tags which render as void elements:
- area
- base
- br
- col
- embed
- hr
- img
- input
- link
- meta
- param
- source
- track
- wbr
This will only affect the output of to_string
and to_string_builder
!
If you need to render any of these tags with children, or you want to
render some other tag as self-closing or void, use advanced
to construct the element instead.
pub fn fragment(elements: List(Element(a))) -> Element(a)
A function for wrapping elements to be rendered within a parent container without specififying the container on definition. Allows the treatment of List(Element(msg)) as if it were Element(msg). Useful when generating a list of elements from data but used downstream.
pub fn keyed(
el: fn(List(Element(a))) -> Element(a),
children: List(#(String, Element(a))),
) -> Element(a)
Keying elements is an optimisation that helps the runtime reuse existing DOM nodes in cases where children are reordered or removed from a list. Maybe you have a list of elements that can be filtered or sorted in some way, or additions to the front are common. In these cases, keying elements can help Lustre avoid unecessary DOM manipulations by pairing the DOM nodes with the elements in the list that share the same key.
You can easily take an element from lustre/element/html
and key its children
by making use of Gleam’s function capturing syntax:
import gleam/list
import lustre/element
import lustre/element/html
fn example() {
element.keyed(html.ul([], _), {
use item <- list.map(todo_list)
let child = html.li([], [view_item(item)])
#(item.id, child)
})
}
Note: The key must be unique within the list of children, but it doesn’t have to be unique across the whole application. It’s fine to use the same key in different lists. Lustre will display a warning in the browser console when it detects duplicate keys in a list.
pub fn map(element: Element(a), f: fn(a) -> b) -> Element(b)
The Element
type is parameterised by the type of messages it can produce
from events. Sometimes you might end up with a fragment of HTML from another
library or module that produces a different type of message: this function lets
you map the messages produced from one type to another.
Think of it like list.map
or result.map
but for HTML events!
pub fn namespaced(
namespace: String,
tag: String,
attrs: List(Attribute(a)),
children: List(Element(a)),
) -> Element(a)
A function for constructing elements in a specific XML namespace. This can be used to construct SVG or MathML elements, for example.
pub fn none() -> Element(a)
A function for rendering nothing. This is mostly useful for conditional rendering, where you might want to render something only if a certain condition is met.
pub fn text(content: String) -> Element(a)
A function for turning a Gleam string into a text node. Gleam doesn’t have
union types like some other languages you may be familiar with, like TypeScript.
Instead, we need a way to take a String
and turn it into an Element
somehow:
this function is exactly that!
pub fn to_document_string(el: Element(a)) -> String
Converts an element to a string like to_string
, but prepends
a <!doctype html>
declaration to the string. This is useful for rendering
complete HTML documents.
If the provided element is not an html
element, it will be wrapped in both
a html
and body
element.
pub fn to_document_string_builder(
el: Element(a),
) -> StringBuilder
Converts an element to a StringBuilder
like to_string_builder
,
but prepends a <!doctype html>
declaration. This is useful for rendering
complete HTML documents.
If the provided element is not an html
element, it will be wrapped in both
a html
and body
element.
pub fn to_readable_string(el: Element(a)) -> String
Converts a Lustre Element
to a human-readable string by inserting new lines
and indentation where appropriate. This is useful for debugging and testing,
but for production code you should use to_string
or
to_document_string
instead.
💡 This function works great with the snapshot testing library birdie!
Using to_string
:
<header><h1>Hello, world!</h1></header>
Using to_readable_string
<header>
<h1>
Hello, world!
</h1>
</header>
pub fn to_string(element: Element(a)) -> String
Convert a Lustre Element
to a string. This is not pretty-printed, so
there are no newlines or indentation. If you need to pretty-print an element,
reach out on the Gleam Discord or
open an issue with your
use case and we’ll see what we can do!
pub fn to_string_builder(element: Element(a)) -> StringBuilder
Convert a Lustre Element
to a StringBuilder
. This is not pretty-printed,
so there are no newlines or indentation. If you need to pretty-print an element,
reach out on the Gleam Discord or
open an issue with your
use case and we’ll see what we can do!