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
- Host: GitHub
- URL: https://github.com/byteface/luadom
- Owner: byteface
- License: mit
- Created: 2026-02-15T22:03:11.000Z (4 months ago)
- Default Branch: master
- Last Pushed: 2026-02-15T22:11:58.000Z (4 months ago)
- Last Synced: 2026-03-11T15:50:31.580Z (3 months ago)
- Language: Lua
- Size: 40 KB
- Stars: 3
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
- Roadmap: ROADMAP.md
Awesome Lists containing this project
README
# luadom
[](https://luarocks.org/modules/luadom/luadom)
[](https://luarocks.org/modules/luadom/luadom)
[](https://github.com/byteface/luadom/actions/workflows/ci.yml)
[](LICENSE)
[](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