Elements & render()

mx.div() returns a lightweight description (an array marked with ._=true). When you pass it into render, mx creates or updates DOM nodes efficiently.

let { div, span } = mx;
let host = dom.div();

// Initial render
host.render(
  div({ class: "box" }, span("A")),
  div({ class: "box" }, span("B"))
);

// Update - re-render the same container, mx patches minimally
host.render(
  div({ class: "box" }, span("A (updated)")),
  div({ class: "box" }, span("B"))
);

document.body.render(host);

Tip

You can render multiple children at once: el.render(head, main, footer). null, undefined, and false are ignored, which makes conditional rendering straightforward.

Attributes & Prefixes

Attributes are passed as the first argument. Use the . prefix to set DOM properties directly:

let { input, button } = mx;

let field = input({
  type: "text",
  placeholder: "Your name",
  ".value": "",         // .prefix sets DOM property directly
  disabled: false,      // false/null removes the attribute
  required: true        // true sets the string "true"
});

let submit = button({ type: "submit" }, "Send");

Property vs Attribute

DOM inputs care about the property value, not the attribute value. Use ".value" to set it. Same for .checked and .selectedIndex.

Events (onclick)

Set event handlers as properties in lowercase: onclick, oninput, onchange, etc.

Important

Use lowercase event names. onClick won't work - it's not React. Write onclick.

let { div, button, span } = mx;

let count = 0;
let host = dom.div();

function Counter() {
  return div(
    button({ onclick() { count--; host.render(Counter()); } }, "−"),
    span(" " + count + " "),
    button({ onclick() { count++; host.render(Counter()); } }, "+")
  );
}

host.render(Counter());
document.body.render(host);

Children

Children can be strings, DOM nodes, or other mx.* arrays.

let { ul, li, strong } = mx;

let list = ul(
  li("One"),
  li(strong("Two")),
  li("Three")
);

SVG Namespace Inheritance

mx.svg() creates an element in the SVG namespace. Any element rendered inside an SVG parent automatically gets the SVG namespace too - you don't need to mark <g>, <path>, <polyline>, or any other nested SVG element specially:

// All children rendered inside <svg> inherit svgNS automatically
mx.svg({ viewBox: '0 0 100 100' },
    mx.g({ transform: 'translate(10, 10)' },
        mx.circle({ cx: 40, cy: 40, r: 30, fill: 'red' }),
        mx.path({ d: 'M0 0 L80 80' })
    )
)

The check is based on the host element's namespaceURI. Nested render() calls re-detect namespace from their own host, so deeply nested SVG trees work correctly.

Known limitation: foreignObject

<foreignObject> is itself in the SVG namespace, but its children should be HTML. mx doesn't special-case this - children of foreignObject get SVG namespace, which breaks HTML rendering inside. If you need HTML inside SVG, build the foreignObject contents with raw document.createElement or use a separate dom() call and insert the resulting node.