Warning: Reason support is experimental. We are looking for beta-tester and contributors.

TyXML JSX syntax

TyXML provides a ppx which allows use Reason's convenient JSX syntax while still enjoying the benefits and type-safety of TyXML. It is available as the tyxml-jsx package:

opam install tyxml-jsx

Syntax

This syntax should be familiar to most Reason users:

# open Tyxml;

# let intro = <span id="hello"> "Hello!" </span>;
let intro: Tyxml_html.elt([> Html_types.span ]) =
  <span id="hello">Hello!</span>;

# let svgpath = <path d="M 0 1 L 1 0" />;
let svgpath: Tyxml_svg.elt([> Svg_types.path ]) =
  <path d="M 0 1 L 1 0"></path>;

The quotations will use the Html and Svg module that are available in scope, but it can also be disambiguated manually by prefixing the namespace.

We can also build list of elements:

# let nice_picture = <> <p>"picture: "</p> <Html.svg> svgpath </Html.svg> </> ;
let nice_picture: list(Tyxml_html.elt([> `P | `Svg ])) =
  [<p>picture: </p>,
   <svg><path d="M 0 1 L 1 0"></path></svg>];

We can nest various elements and use spreads:

# let content = <> intro <div class_="content"> ...nice_picture </div> </>;
let content: list(Tyxml_html.elt([> `Div | `Span ])) =
  [<span id="hello">Hello!</span>,
   <div class="content"><p>picture: </p><svg><path d="M 0 1 L 1 0"></path></svg></div>];

Finally, we can insert custom elements:

# module Page = {
  let createElement = (~title, ~children, ()) => {
    <html>
      <head>
        <title> {Html.txt(title)} </title>
        <link rel="stylesheet" href="home.css" />
      </head>
      <body> ...children </body>
    </html>
  };
};
module Page:
  {
    let createElement:
      (~title: string,
      ~children: list(Html.elt([< Html_types.object__content_fun ])),
      unit) => Html.doc;
  };

# let this_title = "Weeee";
# let page = 
  <Page title=this_title>
    ...content
  </Page>;
let page: Html.doc = ....

In the previous examples, we used the textual implementation of tyxml (module Tyxml) in the tyxml library), but it works equally well with other implementations: - The DOM tree with the js_of_ocaml-tyxml library. Either the Error a_api: exception Dune__exe__Api.Error("invalid contents: Js_of_ocaml_tyxml.Tyxml_js") or the reactive version in Error a_api: exception Dune__exe__Api.Error("invalid contents: Js_of_ocaml_tyxml.Tyxml_js.R"). - The virtual_dom library with the module Virtual_dom.Tyxml.

In each case, simply open the module and the JSX syntax will use it.

"Unsafe" attributes

Some Javascript libraries and frameworks depend upon HTML markup that includes non-standard attributes, which tyxml would usually reject. When constructing elements using tyxml's API directly, the available workaround is to use the Error a_api: exception Dune__exe__Api.Error("invalid ocaml id \"Html_sigs.T.Unsafe\"") constructors. The same relaxed semantics can be had when using JSX by prefixing non-standard attribute names with a leading underscore.

So, while this will fail:

let button = <button hx_post="/clicked" hx_swap="outerHTML">Click Me</button>

This will not:

let button = <button _hx_post="/clicked" _hx_swap="outerHTML">Click Me</button>

Such underscore-prefixed attributes are presumed to be strings, and are constructed using e.g. Unsafe.string_attrib.

Tips

It can sometime be necessary to disable the JSX syntax. For that purpose, simply use the toogle `[@tyxml.jsx false]` to turn the JSX on and off.