An open API service indexing awesome lists of open source software.

https://github.com/byteface/luadom

A tiny DOM-ish HTML builder for Lua
https://github.com/byteface/luadom

Last synced: about 2 months ago
JSON representation

A tiny DOM-ish HTML builder for Lua

Awesome Lists containing this project

README

          

# luadom

[![LuaRocks](https://img.shields.io/luarocks/v/luadom/luadom?label=LuaRocks)](https://luarocks.org/modules/luadom/luadom)
[![LuaRocks Downloads](https://img.shields.io/luarocks/dt/luadom/luadom?label=Downloads)](https://luarocks.org/modules/luadom/luadom)
[![CI](https://github.com/byteface/luadom/actions/workflows/ci.yml/badge.svg)](https://github.com/byteface/luadom/actions/workflows/ci.yml)
[![License](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)
[![Latest Tag](https://img.shields.io/github/v/tag/byteface/luadom?label=Tag)](https://github.com/byteface/luadom/tags)

A tiny DOM-ish HTML builder for Lua inspired by [domonic](https://github.com/byteface/domonic). Build HTML with tag functions, props tables, and a DOM-style query API, then render to a string. This is server-side only.

## Requirements

- Lua 5.1+ (tested with 5.4)
- LuaRocks (for packaging/publishing and examples)

## Installing LuaRocks

macOS (Homebrew):

```sh
brew install lua
brew install luarocks
```

Linux/Unix:

Use the official LuaRocks install instructions (tarball build) from their site (the Quick Start section shows the current commands).

Windows:

Use the official LuaRocks Windows installer instructions.

Reference links:

```text
https://luarocks.org/
https://formulae.brew.sh/formula/luarocks
https://github.com/luarocks/luarocks/wiki/Installation-instructions-for-Windows/91bc512e3f7298e27ad1a8cbfab4c5075adf1187
```

## Quick Start

1. From this folder, run the basic example:

```sh
lua examples/helloworld.lua
```

2. Open `index.html` to see the output.

## Examples

- Basic: `lua examples/helloworld.lua`
- Full homepage showcase: `lua examples/homepage.lua`
- More examples: see `examples/README.md`

All examples that render files write to `index.html` in the project root.

## Examples (More)

See `examples/README.md` for runnable examples, including servers using LuaSocket, lua-http, and Lapis.

## Usage

Minimal example:

```lua
require("html")

local page = html(
head(
meta({ charset = "utf-8" }),
title("Hello World")
),
body(
div({ _class = "container" },
h1("Hello World"),
p("Generated with luadom.")
)
)
)

local html_out = render(page)
print(html_out)
```

If you prefer explicit namespacing instead of globals:

```lua
local dom = require("luadom")

local page = dom.html(
dom.body(
dom.h1("Hello")
)
)

local html_out = dom.render(page)
```

## Props and Attributes

Props are passed as the first argument using a Lua table:

```lua
div({
id = "main",
_class = "hero",
style = { padding = "16px", background = "#fff" },
hidden = true,
data = { role = "banner" },
}, "Hello")
```

Notes:

- `_class` is converted to `class`
- `for_` is converted to `for` (since `for` is a Lua keyword)
- SVG/DOM sugar: `strokeWidth`, `textAnchor`, `fontSize`, `stopColor`, etc. are mapped to their dashed forms.
- `style` can be a table and will be rendered as CSS
- `data` can be a table and becomes `data-*` attributes
- `true` renders boolean attributes (e.g. `hidden`)
- When using `require("html")`, global tag names can collide with Lua globals. We remap:
- `table` -> HTML `` tag (original Lua table library is available as `table_lib`)
- `select` -> HTML `` tag (original Lua `select` is available as `select_fn`)
- Use `raw(...)` for `` or `<style>` contents to avoid escaping.

## Query Helpers (DOM-style)

Available on any node:

```lua
local root = html(...)
local el = root:querySelector(".card")
local by_id = root:getElementById("main")
local all = root:getElementsByTagName("section")
```

Selector support includes:

- Tag name (e.g. `"div"`)
- Id (e.g. `"#main"`)
- Class (e.g. `".card"`)
- Compound selectors (e.g. `"section.card#main"`)
- Descendant and child (`"div span"`, `"div > span"`)
- Attribute selectors (`"[title=x]"`, `"[data-role=hero]"`)
- Attribute operators (`^=`, `$=`, `*=`) (e.g. `"[title^=hello]"`)
- Selector lists (`"div, span"`)
- Pseudo-classes: `:first-child`, `:last-child`, `:nth-child(n)`
- Sibling combinators: `+`, `~`
- `:not(...)` (simple selector)

## DOM Methods

Available on element nodes:

- `matches(selector)`
- `closest(selector)`
- `contains(node)`
- `appendChild(node)`
- `removeChild(node)`
- `replaceChild(newNode, oldNode)`
- `cloneNode(deep)`
- `setAttribute(name, value)`
- `getAttribute(name)`
- `removeAttribute(name)`
- `textContent([value])`
- `innerHTML([value])` (setter stores raw HTML)
- `addClass(...)`, `removeClass(...)`, `toggleClass(class, force)`, `hasClass(class)`
- `classList()` (returns `add/remove/toggle/contains`)
- `style()` and `dataset()` helpers (table accessors)
- `parentNode()`, `childNodes()`, `firstChild()`, `lastChild()`, `nextSibling()`, `previousSibling()`
- Node constants (`ELEMENT_NODE`, `TEXT_NODE`, etc.) available via `dom.__node_constants`

## Tag Validation

All tags are created dynamically. Non-standard tags will warn by default (custom elements with a dash are allowed).

```lua
local dom = require("luadom")

-- modes: "warn" (default), "error", "off"
dom.setTagValidation("warn")
```

## Pretty Rendering

```lua
local html = dom.renderPretty(page)
```

Options:

```lua
dom.render(page, { pretty = true, indent = " ", newline = "\n" })
```

## JS-style Timers

These are cooperative and run in Lua (server-side).

```lua
local id = dom.setTimeout(function()
print("fired")
end, 1000)

dom.setInterval(function()
print("tick")
end, 500)

-- manually advance timers
dom.tickTimers()

-- intervals with 0ms fire on every tick

-- or run a loop for N milliseconds
dom.runTimers(2000)
```

## JS Helpers

`dom.console` provides `log`, `warn`, `error`.
`dom.document` provides `createElement`, `createElementNS`, `createTextNode`, `createDocumentFragment`, `createComment`, `createHTMLDocument`.
`dom.Document` creates a document wrapper with `head` and `body`.

## Files

- `dom.lua` - core nodes, rendering, selectors
- `luadom.lua` - tag factory and public API
- `html.lua` - global helpers (`div(...)`, `render(...)`, etc.)
- `js.lua` - JS-style timer helpers
- `svg.lua` - SVG tag helpers (similar to `html.lua`)
- `examples/` - runnable examples

## Notes

This is a server-side HTML builder. It does not execute JS or provide a browser runtime. HTML parsing is not included. A `<!doctype html>` is automatically prepended when rendering a root `<html>` element (disable via `{ doctype = false }`).

## Tests

Run the test suite:

```sh
lua tests/run.lua
```

GitHub Actions runs this on Lua 5.1–5.4.

## Docs (LDoc)

Install and generate docs:

```sh
luarocks install ldoc
ldoc .
```

Output will be in `docs/`.

Source files for docs live in `docs-src/`.

## Troubleshooting

Command not found: `luarocks`

- Install LuaRocks (see "Installing LuaRocks" above).

Module not found (e.g. `module 'socket' not found`)

- Install the dependency with LuaRocks, e.g. `luarocks install luasocket`.

## Publishing (LuaRocks)

This section shows how to package and publish `luadom` to LuaRocks.

### 1) Add metadata files

Create a `rockspec` file (example below) and a `LICENSE` file. Pick a license (MIT is common).

Example `luadom-2026.02.08-1.rockspec`:

```lua
package = "luadom"
version = "2026.02.08-1"

source = {
url = "git://github.com/byteface/luadom.git",
tag = "v2026.02.08",
}

description = {
summary = "DOM-ish HTML builder for Lua",
detailed = "Build HTML with tag functions, props tables, and a DOM-style query API.",
homepage = "https://github.com/byteface/luadom",
license = "MIT",
}

dependencies = {
"lua >= 5.1",
}

build = {
type = "builtin",
modules = {
["luadom"] = "luadom.lua",
["dom"] = "dom.lua",
["html"] = "html.lua",
}
}
```

### 2) Tag a release

```sh
git tag v2026.02.08
git push origin v2026.02.08
```

### 3) Build & test the rock locally

```sh
luarocks pack luadom-2026.02.08-1.rockspec
luarocks install luadom-2026.02.08-1.rockspec
lua -e 'require("luadom")'
```

### 4) Publish to LuaRocks

```sh
luarocks upload luadom-2026.02.08-1.rockspec
```

### 5) Install from LuaRocks (users)

```sh
luarocks install luadom
```

### Versioning

This project uses date-based versioning. Update the rockspec version and git tag together (e.g., `2026.03.01-1` and `v2026.03.01`).

## Next Ideas

- More complete CSS selector support
- Pretty/indented HTML rendering
- Timer helpers (`setTimeout`, `setInterval`) with a small scheduler
- LuaRock packaging