lustre/element

Types

pub external type Element(msg)

Functions

pub fn a(attrs: List(Attribute(a)), children: List(Element(a))) -> Element(
  a,
)
pub fn abbr(attrs: List(Attribute(a)), children: List(Element(a))) -> Element(
  a,
)
pub fn address(attrs: List(Attribute(a)), children: List(
    Element(a),
  )) -> Element(a)
pub fn area(attrs: List(Attribute(a))) -> Element(a)
pub fn article(attrs: List(Attribute(a)), children: List(
    Element(a),
  )) -> Element(a)
pub fn aside(attrs: List(Attribute(a)), children: List(Element(a))) -> Element(
  a,
)
pub fn audio(attrs: List(Attribute(a)), children: List(Element(a))) -> Element(
  a,
)
pub fn b(attrs: List(Attribute(a)), children: List(Element(a))) -> Element(
  a,
)
pub fn base(attrs: List(Attribute(a))) -> Element(a)
pub fn bdi(attrs: List(Attribute(a)), children: List(Element(a))) -> Element(
  a,
)
pub fn bdo(attrs: List(Attribute(a)), children: List(Element(a))) -> Element(
  a,
)
pub fn blockquote(attrs: List(Attribute(a)), children: List(
    Element(a),
  )) -> Element(a)
pub fn body(attrs: List(Attribute(a)), children: List(Element(a))) -> Element(
  a,
)
pub fn br(attrs: List(Attribute(a))) -> Element(a)
pub fn button(attrs: List(Attribute(a)), children: List(
    Element(a),
  )) -> Element(a)
pub fn canvas(attrs: List(Attribute(a)), children: List(
    Element(a),
  )) -> Element(a)
pub fn caption(attrs: List(Attribute(a)), children: List(
    Element(a),
  )) -> Element(a)
pub fn cite(attrs: List(Attribute(a)), children: List(Element(a))) -> Element(
  a,
)
pub fn code(attrs: List(Attribute(a)), children: List(Element(a))) -> Element(
  a,
)
pub fn col(attrs: List(Attribute(a)), children: List(Element(a))) -> Element(
  a,
)
pub fn colgroup(attrs: List(Attribute(a)), children: List(
    Element(a),
  )) -> Element(a)
pub fn datalist(attrs: List(Attribute(a)), children: List(
    Element(a),
  )) -> Element(a)
pub fn dd(attrs: List(Attribute(a)), children: List(Element(a))) -> Element(
  a,
)
pub fn del(attrs: List(Attribute(a)), children: List(Element(a))) -> Element(
  a,
)
pub fn details(attrs: List(Attribute(a)), children: List(
    Element(a),
  )) -> Element(a)
pub fn dfn(attrs: List(Attribute(a)), children: List(Element(a))) -> Element(
  a,
)
pub fn dialog(attrs: List(Attribute(a)), children: List(
    Element(a),
  )) -> Element(a)
pub fn div(attrs: List(Attribute(a)), children: List(Element(a))) -> Element(
  a,
)
pub fn dl(attrs: List(Attribute(a)), children: List(Element(a))) -> Element(
  a,
)
pub fn dt(attrs: List(Attribute(a)), children: List(Element(a))) -> Element(
  a,
)
pub fn em(attrs: List(Attribute(a)), children: List(Element(a))) -> Element(
  a,
)
pub fn embed(attrs: List(Attribute(a))) -> Element(a)
pub fn fieldset(attrs: List(Attribute(a)), children: List(
    Element(a),
  )) -> Element(a)
pub fn figcaption(attrs: List(Attribute(a)), children: List(
    Element(a),
  )) -> Element(a)
pub fn figure(attrs: List(Attribute(a)), children: List(
    Element(a),
  )) -> Element(a)
pub fn footer(attrs: List(Attribute(a)), children: List(
    Element(a),
  )) -> Element(a)
pub fn form(attrs: List(Attribute(a)), children: List(Element(a))) -> Element(
  a,
)
pub external fn fragment(
  children: List(Element(msg)),
) -> Element(msg)

A fragment doesn’t appear in the DOM, but allows us to treat a list of elements as if it were a single one.

pub fn h1(attrs: List(Attribute(a)), children: List(Element(a))) -> Element(
  a,
)
pub fn h2(attrs: List(Attribute(a)), children: List(Element(a))) -> Element(
  a,
)
pub fn h3(attrs: List(Attribute(a)), children: List(Element(a))) -> Element(
  a,
)
pub fn h4(attrs: List(Attribute(a)), children: List(Element(a))) -> Element(
  a,
)
pub fn h5(attrs: List(Attribute(a)), children: List(Element(a))) -> Element(
  a,
)
pub fn h6(attrs: List(Attribute(a)), children: List(Element(a))) -> Element(
  a,
)
pub fn head(attrs: List(Attribute(a)), children: List(Element(a))) -> Element(
  a,
)
pub fn header(attrs: List(Attribute(a)), children: List(
    Element(a),
  )) -> Element(a)
pub fn hr(attrs: List(Attribute(a))) -> Element(a)
pub fn html(attrs: List(Attribute(a)), head: Element(a), body: Element(
    a,
  )) -> Element(a)
pub fn i(attrs: List(Attribute(a)), children: List(Element(a))) -> Element(
  a,
)
pub fn iframe(attrs: List(Attribute(a))) -> Element(a)
pub fn img(attrs: List(Attribute(a))) -> Element(a)
pub fn input(attrs: List(Attribute(a))) -> Element(a)
pub fn ins(attrs: List(Attribute(a)), children: List(Element(a))) -> Element(
  a,
)
pub fn kbd(attrs: List(Attribute(a)), children: List(Element(a))) -> Element(
  a,
)
pub fn label(attrs: List(Attribute(a)), children: List(Element(a))) -> Element(
  a,
)
pub fn legend(attrs: List(Attribute(a)), children: List(
    Element(a),
  )) -> Element(a)
pub fn li(attrs: List(Attribute(a)), children: List(Element(a))) -> Element(
  a,
)
pub fn main(attrs: List(Attribute(a)), children: List(Element(a))) -> Element(
  a,
)
pub external fn map(
  element: Element(a),
  f: fn(a) -> b,
) -> Element(b)

Transforms the actions produced by an element. Our Lustre applications have a single top-level Msg type and update function, and ultimately all elements we create must produce actions of that type (or not produce any at all).

To save us having a monolothic Msg type with many constructors, we can crete child types and then use map to wrap them up in the parent type. A simple counter with its own message type my look like this:

import gleam/int
import lustre/element.{Element}
import lustre/event

type Msg {
  Decr
  Incr
}

pub fn update(count: Int, msg: CounterMsg) -> Int {
  case msg {
    Decr -> count - 1
    Incr -> count + 1
  }
}

pub fn render(count: Int) -> Element(CounterMsg) {
  element.div([], [
    element.button([event.on_click(Decr)], [element.text("-")]),
    element.text(int.to_string(count)),
    element.button([event.on_click(Incr)], [element.text("+")]),
  ])
}

To integrate this into a large Lustre application, we need to do some plumbing. Here’s how we might have a parent application that renders multiple counters:

import counter.{Msg as CounterMsg}
import gleam/list
import gleam/map.{Map}
import gleam/result
import lustre
import lustre/element.{Element}
import lustre/event

pub fn main() {
  let app = lustre.simple(init(), update, render)
  assert Ok(_) = lustre.start(app, "#root")
}

type Model = Map(Int, Int)

fn init() -> Model {
  map.from_list([
    #(0, 0),
    #(1, 0),
    #(2, 0),
  ])
}

type Msg {
  UpdateCounter(Int, CounterMsg)
}

pub fn update(model: Model, msg: Msg) -> Model {
  case msg {
    UpdateCounter(id, counter_msg) -> {
      map.get(model, id)
      // Call the counter's update function with the `counter_msg`. This will
      // either be `counter.Decr` or `counter.Incr`.
      |> result.map(counter.update(_, counter_msg))
      |> result.map(map.insert(model, id, _))
      |> result.unwrap(model)
    }
  }
}

pub fn render(model: Model) -> Element(Msg) {
  let counters = {
    use els, id, count <- map.fold(model, [])
    let counter = counter.render(counr)

    // Right now `counter` produces messages of type `counter.Msg`. Here we're
    // calling `element.map` to wrap that message in our main app's `Msg` type.
    [element.map(counter, UpdateCounter(id, _)), ...els]
  }

  element.div([], list.reverse(counters))
}

If this feels like a lt of work… sometimes it is! Take a look at the docs for stateful elements to see how all this can be encapsulated.

pub fn map_(attrs: List(Attribute(a)), children: List(Element(a))) -> Element(
  a,
)
pub fn mark(attrs: List(Attribute(a)), children: List(Element(a))) -> Element(
  a,
)
pub fn mathml(attrs: List(Attribute(a)), children: List(
    Element(a),
  )) -> Element(a)
pub fn menu(attrs: List(Attribute(a)), children: List(Element(a))) -> Element(
  a,
)
pub fn meta(attrs: List(Attribute(a))) -> Element(a)
pub fn meter(attrs: List(Attribute(a)), children: List(Element(a))) -> Element(
  a,
)
pub fn nav(attrs: List(Attribute(a)), children: List(Element(a))) -> Element(
  a,
)
pub external fn node(
  tag: String,
  attrs: List(Attribute(msg)),
  children: List(Element(msg)),
) -> Element(msg)

Construct a plain HTML element or registered Web Component by providing the tag name, a list of attributes (including event handlers), and a list of child elements.

pub fn noscript(attrs: List(Attribute(a)), children: List(
    Element(a),
  )) -> Element(a)
pub fn object(attrs: List(Attribute(a)), children: List(
    Element(a),
  )) -> Element(a)
pub fn ol(attrs: List(Attribute(a)), children: List(Element(a))) -> Element(
  a,
)
pub fn optgroup(attrs: List(Attribute(a)), children: List(
    Element(a),
  )) -> Element(a)
pub fn option(attrs: List(Attribute(a)), children: List(
    Element(a),
  )) -> Element(a)
pub fn output(attrs: List(Attribute(a)), children: List(
    Element(a),
  )) -> Element(a)
pub fn p(attrs: List(Attribute(a)), children: List(Element(a))) -> Element(
  a,
)
pub fn param(attrs: List(Attribute(a)), children: List(Element(a))) -> Element(
  a,
)
pub fn picture(attrs: List(Attribute(a)), children: List(
    Element(a),
  )) -> Element(a)
pub fn portal(attrs: List(Attribute(a))) -> Element(a)
pub fn pre(attrs: List(Attribute(a)), children: List(Element(a))) -> Element(
  a,
)
pub fn progress(attrs: List(Attribute(a)), children: List(
    Element(a),
  )) -> Element(a)
pub fn rp(attrs: List(Attribute(a)), children: List(Element(a))) -> Element(
  a,
)
pub fn rt(attrs: List(Attribute(a)), children: List(Element(a))) -> Element(
  a,
)
pub fn ruby(attrs: List(Attribute(a)), children: List(Element(a))) -> Element(
  a,
)
pub fn s(attrs: List(Attribute(a)), children: List(Element(a))) -> Element(
  a,
)
pub fn samp(attrs: List(Attribute(a)), children: List(Element(a))) -> Element(
  a,
)
pub fn section(attrs: List(Attribute(a)), children: List(
    Element(a),
  )) -> Element(a)
pub fn select(attrs: List(Attribute(a)), children: List(
    Element(a),
  )) -> Element(a)
pub fn slot(attrs: List(Attribute(a)), children: List(Element(a))) -> Element(
  a,
)
pub fn small(attrs: List(Attribute(a)), children: List(Element(a))) -> Element(
  a,
)
pub fn source(attrs: List(Attribute(a))) -> Element(a)
pub fn span(attrs: List(Attribute(a)), children: List(Element(a))) -> Element(
  a,
)
pub external fn stateful(
  init: state,
  render: fn(state, fn(state) -> Nil) -> Element(msg),
) -> Element(msg)

A stateful element is exactly what it sounds like: an element with local encapsulated state! The render function we must provide is called with the element’s current state as well as a function to set a new state. Whenever that function is called, the element is re-rendered.

You might be wondering where the stateless version of this function is. Those are just regular Gleam functions that return Elements!

We can implement a counter whose current value is stored locally like so:

import gleam/int
import lustre/attribute.{Attribute}
import lustre/element.{Element}
import lustre/event

pub fn counter() -> Element(msg) {
  use state, set_state = lustre.stateful(0)

  let decr = event.on("click", fn(_, _) { set_state(state - 1) })
  let incr = event.on("click", fn(_, _) { set_state(state + 1) })

  element.div([], [
    element.button([decr], [element.text("-")]),
    element.text(int.to_string(state)),
    element.button([incr], [element.text("+")]),
  ])
}

We can use this counter element anywhere in our app, we don’t have to worry about passing state around or managing it in a parent component.

When attaching event handlers to stateful elements, you’ll typically have to use the generic event.on function rather than the more specific helpders. The helpers are designed to emit messages for your application, but stateful elements don’t necessarily produce messages: calling set_state is a side effect.

pub fn strong(attrs: List(Attribute(a)), children: List(
    Element(a),
  )) -> Element(a)
pub fn style(attrs: List(Attribute(a)), css: String) -> Element(a)
pub fn sub(attrs: List(Attribute(a)), children: List(Element(a))) -> Element(
  a,
)
pub fn summary(attrs: List(Attribute(a)), children: List(
    Element(a),
  )) -> Element(a)
pub fn sup(attrs: List(Attribute(a)), children: List(Element(a))) -> Element(
  a,
)
pub fn svg(attrs: List(Attribute(a)), children: List(Element(a))) -> Element(
  a,
)
pub fn table(attrs: List(Attribute(a)), children: List(Element(a))) -> Element(
  a,
)
pub fn tbody(attrs: List(Attribute(a)), children: List(Element(a))) -> Element(
  a,
)
pub fn td(attrs: List(Attribute(a)), children: List(Element(a))) -> Element(
  a,
)
pub fn template(attrs: List(Attribute(a)), children: List(
    Element(a),
  )) -> Element(a)
pub external fn text(content: String) -> Element(msg)

Render a Gleam string as an HTML text node.

pub fn textarea(attrs: List(Attribute(a))) -> Element(a)
pub fn tfoot(attrs: List(Attribute(a)), children: List(Element(a))) -> Element(
  a,
)
pub fn th(attrs: List(Attribute(a)), children: List(Element(a))) -> Element(
  a,
)
pub fn thead(attrs: List(Attribute(a)), children: List(Element(a))) -> Element(
  a,
)
pub fn time(attrs: List(Attribute(a)), children: List(Element(a))) -> Element(
  a,
)
pub fn title(attrs: List(Attribute(a)), name: String) -> Element(
  a,
)
pub fn tr(attrs: List(Attribute(a)), children: List(Element(a))) -> Element(
  a,
)
pub fn track(attrs: List(Attribute(a)), children: List(Element(a))) -> Element(
  a,
)
pub fn u(attrs: List(Attribute(a)), children: List(Element(a))) -> Element(
  a,
)
pub fn ul(attrs: List(Attribute(a)), children: List(Element(a))) -> Element(
  a,
)
pub fn var_(attrs: List(Attribute(a)), children: List(Element(a))) -> Element(
  a,
)
pub fn video(attrs: List(Attribute(a)), children: List(Element(a))) -> Element(
  a,
)
pub fn wbr(attrs: List(Attribute(a))) -> Element(a)
Search Document