mmm​.s‑ol.nu

fun stuff with code and wires
an error occured while rendering this view:

mmm.dom

mmm.dom is a lightweight DSL for creating HTML documents in Lua and Moonscript.

The same API is supported both on the server / in native Lua, where it outputs an HTML string, as well as on the client (using fengari.io), where it dynamically creates DOM Nodes that can be further manipulated using Lua or JavaScript. The API behaves exactly the same way in both modes so that you can write code once that works both for rendering offline/serverside and in the browser. This enables you to build websites and applications with dynamic content as well as perfect static views for clients with JS disabled and SEO.

API

Begin by requiring mmm.dom. The module returns a 'magic table' that allows you to instantiate HTML elements of any type. Compare the usage in Lua and Moonscript:

import div, h1, p, a from require 'mmm.dom'

-- or just use dom.div etc. if you want to keep your
-- namespace clean, they are cached automatically

dom = require 'mmm.dom'
local dom = require 'mmm.dom'

local div, h1, p, a = dom.div, dom.h1, dom.p, dom.a

-- or just use dom.div etc. if you want to keep your
-- namespace clean, they are cached automatically

Each of these constructor functions can now be used to instantiate elements of the specified type. In the simplest case, you may want to a simple element with no attributes or children, for example a
line break tag:

import br from require 'mmm.dom'

br!
local dom = require 'mmm.dom'

return dom.br()

You can pass any number of children as arguments when you create an element. They will be joined without spaces:

import h3, i, code from require 'mmm.dom'

h3 "this is a ",
  (i 'headline'),
  " with some ",
  code 'rich text'
local d = require 'mmm.dom'

return d.h3(
  "this is a ",
  d.i 'headline',
  " with some ",
  d.code 'rich text'
)

this is a headline with some rich text

As you can see, mmm.dom can be used quite comfortably both in Lua and Moonscript.

As you build bigger structures, you may find that constructing HTML trees via argument lists can get a bit confusing (especially with Moonscript and indentation rules). Because of this mmm.dom also supports passing a table with children in the integer keys 1, 2, ... This is particularily useful when you make use of Lua's shorthand for calling functions with single arguments:

import article, h3, span, div, i, p from require 'mmm.dom'

article {
  h3 "This is a headline with ", i "cursive text"
  p {
    "The content goes ",
    i "here."
  }
  p "more paragraphs can be added as well, of course."
}
local dom = require 'mmm.dom'
local article, h3, span, div, i, p = dom.article, dom.h3, dom.span, dom.div, dom.i, dom.p

return article{
  h3{ "This is a headline with ", i "cursive text" },
  p{
    "The content goes ",
    i"here."
  },
  p"more paragraphs can be added as well, of course."
}

This is a headline with cursive text

The content goes here.

more paragraphs can be added as well, of course.

Of course mmm.dom also allows you to set attributes on elements.

When you are using a constructor using the single-table approach, all string keys set on the table are considered attributes and set on the element:

import div from require 'mmm.dom'

div {
  id: 'my_div',
  class: 'shadow',
  "This is div matches the CSS selector `div#my_div.shadow`"
}
local div = require('mmm.dom').div

return div{
  id = 'my_div',
  class = 'shadow',
  "This is div matches the CSS selector `div#my_div.shadow`"
}
This is div matches the CSS selector `div#my_div.shadow`

When you are passing multiple arguments, you can attach the attributes in a table as the last argument. This works very well with Moonscript syntax.

In general attribute values need to be strings or numbers to be rendered correctly both on client on server. The only exception is the style attribute, which, if it is passed as a table, will be expanded into a valid CSS string:

import div from require 'mmm.dom'

div "red div with white text", style: {
  background: 'red',
  color: '#ffffff',
}
local div = require('mmm.dom').div

return div(
  "red div with white text",
  {
    style = {
      background = 'red',
      color = '#ffffff',
    }
  }
)
red div with white text