1 Node-API
Virgil edited this page 2026-02-19 16:41:33 +00:00

Node API

The Node interface is the fundamental building block. All rendered elements implement it.

See also: Home | Architecture | Pipeline | WebAssembly | Code-Generation

Node Interface

type Node interface {
    Render(ctx *Context) string
}

Every node receives a Context and returns an HTML string. Nodes compose into trees via El() children.

Node Types

Text — i18n-Aware Text

func Text(key string, args ...any) Node

Renders localised text through the i18n service in the context. Output is HTML-escaped (safe by default). Supports fmt.Sprintf-style arguments.

html.Text("greeting", userName)
// Looks up "greeting" in locale, formats with userName
// Output: "Hello, Alice" (escaped)

El — HTML Element

func El(tag string, children ...Node) Node

Creates an HTML element. Children are rendered in order. Void elements (br, img, hr, input, meta, link, area, base, col, embed, source, track, wbr) self-close.

html.El("div",
    html.El("h1", html.Text("page.title")),
    html.El("p", html.Text("page.body")),
)
// <div><h1>Page Title</h1><p>Body text</p></div>

Attr — Attribute Setter

func Attr(n Node, key, value string) Node

Sets an attribute on an element node. Returns the same node for chaining. Values are attribute-escaped.

html.Attr(
    html.El("a", html.Text("link.text")),
    "href", "/about",
)
// <a href="/about">About</a>

Raw — Unescaped Content

func Raw(content string) Node

Renders content without escaping. Use only for trusted content (pre-sanitised HTML, SVG, etc.).

html.Raw("<svg>...</svg>")

If — Conditional Rendering

func If(cond func(*Context) bool, node Node) Node

Renders the node only when the condition returns true. The condition receives the current context.

html.If(
    func(ctx *html.Context) bool { return ctx.Identity != "" },
    html.El("span", html.Text("user.welcome")),
)

Unless — Negated Conditional

func Unless(cond func(*Context) bool, node Node) Node

Renders the node when the condition is false. Inverse of If.

html.Unless(
    func(ctx *html.Context) bool { return ctx.Identity != "" },
    html.El("a", html.Text("auth.login")),
)

Entitled — Feature Gate

func Entitled(feature string, node Node) Node

Renders the node only if the feature is present in ctx.Entitlements. Used for plan/tier-gated UI.

html.Entitled("analytics-pro",
    html.El("div", html.Text("analytics.advanced_panel")),
)

Switch — Runtime Case Selection

func Switch(selector func(*Context) string, cases map[string]Node) Node

Evaluates the selector at render time and renders the matching case. No output if no case matches.

html.Switch(
    func(ctx *html.Context) string { return ctx.Data["theme"] },
    map[string]html.Node{
        "dark":  html.El("div", html.Attr(html.El("div"), "class", "dark")),
        "light": html.El("div", html.Attr(html.El("div"), "class", "light")),
    },
)

Each — Generic Iteration

func Each[T any](items []T, fn func(T) Node) Node

Iterates over a typed slice, calling the function for each item. Uses Go generics.

type Article struct { Title, Slug string }

html.Each(articles, func(a Article) html.Node {
    return html.El("li",
        html.Attr(html.El("a", html.Text(a.Title)), "href", "/"+a.Slug),
    )
})

Context

type Context struct {
    Identity     string
    Locale       string
    Entitlements map[string]bool
    Data         map[string]string
    Service      *i18n.Service
}

func NewContext() *Context
func NewContextWithService(svc *i18n.Service) *Context
Field Purpose
Identity Current user identifier
Locale Language code for i18n lookups
Entitlements Feature flags for Entitled() gating
Data Arbitrary string data for Switch() selectors
Service go-i18n service for Text() rendering

Convenience

func Render(node Node, ctx *Context) string

Shorthand for node.Render(ctx). Useful in pipelines.