Skill v1.0.0
currentLLM-judged scan90/100version: "1.0.0" name: mlx-syntax description: Syntax guide for mlx, the JSX syntax for OCaml. Use when writing, reading, or reviewing a .mlx file, when the user asks for JSX or HTML-like elements in OCaml, or when a function must be callable as an mlx tag.
Requisite
If the project has no mlx dialect yet, run the setup-mlx skill first.
mlx syntax
mlx is a super-set of OCaml with html-like expressions added. Everything else is plain OCaml, and a .mlx file can hold ordinary OCaml code. An element is an html-like expression: bind it, return it from a match arm, put it in a list, or pass it as an argument without parentheses
Elements are function calls
<div a=1>x</div> calls the function div with ~a:1, ~children:[x], and a final (). A lowercase tag names a function in scope. An uppercase tag names a module and calls its createElement; a runtime ppx may map that call to make. In a module path the last segment decides: <Ui.button /> calls Ui.button, <Ui.Button /> calls Ui.Button.createElement. A self-closing tag passes ~children:[]. The closing tag repeats the opening name.
let page = <html><body><App title="Hi" /></body></html>let items = [<li>"a"</li>; <li>"b"</li>]let _ = render <App title="Hi" />
Props
name=value passes ~name:value. A bare name puns ~name:name. ?name passes an optional argument through, and ?name=value passes ?name:value.
<input value ?placeholder disabled=(not editable) onChange=(fun e -> set e) />
OCaml keywords as prop names
OCaml keywords are not prop names: class, type, method, open are syntax errors. Use the trailing-underscore label the component defines, such as class_.
Children
Children are simple expressions separated by whitespace: literals, identifiers, field access, parenthesized expressions, and elements. They arrive as one list in ~children. A string literal is a plain string; the runtime decides how it renders.
<div>"Total: " (string_of_int total)<span class_="hint">hint</span></div>
Component signature
A function is callable as a tag when its props are labeled arguments, it takes ~children or ?children, and it ends with unit. Declare ~children on a leaf component too: every call passes it. An uppercase tag needs a module whose createElement has the same shape.
let leaf ~title ~children () = ...let button ?(kind = `Primary) ~children () = ...module Card = structlet createElement ~title ~children () = ...endlet _ = <Card title="t"><leaf title="x" /><button kind=`Danger>"Save"</button></Card>
Parenthesize compound expressions
A prop value or a child must be a simple expression. Wrap if, match, fun, let, infix operators, negative numbers, and applications with arguments in parentheses. Braces are an OCaml record literal, so {x} is a record, not interpolation.
(* wrong: syntax error *)<div count=-1 onClick=fun _ -> go ()> if ok then a else b </div>(* right *)<div count=(-1) onClick=(fun _ -> go ())> (if ok then a else b) </div>
Known limits
- Fragments
<>...</>do not exist. Wrap the children in an element or use
a list of elements. If you use reason-react use <React.Fragment>
- Spread
...propsand...childrendo not exist. Forward children with a
children prop, <Child children />
- Comments
(* ... *)are allowed between props and between children.