Conventions
Start hereHow a name, a namespace, a data attribute, an optional prop and a spread from Solid's documentation are written in OCaml.
Solid’s and Kobalte’s documentation is the reference for what a component does. These rules say how to write what it shows in OCaml, so that it reads across without a table per component.
Every name you write is snake case, made by one rule from the name Solid’s or Kobalte’s documentation gives: a capital is an underscore and the lower case, a run of capitals one word, a hyphen an underscore, and an OCaml keyword takes a trailing underscore.
| Solid | OCaml |
|---|---|
onClick |
on_click |
readOnly |
read_only |
aria-label |
aria_label |
defaultValue |
default_value |
classList |
class_list |
createSignal |
create_signal |
a keyword: class, type, for, open, when |
class_, type_, for_, open_, when_ |
The ppx gives each name back its JavaScript spelling by the rule’s inverse,
and by a table of the few the inverse cannot give, such as stroke-width.
A module keeps its JavaScript name: Solid’s ErrorBoundary is
Solidtype.ErrorBoundary, Kobalte’s Switch.Root is
Solidtype_kobalte.Switch.Root.
A handler takes the event its element and name give it: on_click a
Dom.mouseEvent, on_input a Dom.inputEvent.
Namespaces
Section titled “Namespaces”One of Solid’s namespaces wraps the value, never the name: ns:name={v}
is name=(Jsx.ns v).
| Solid | OCaml |
|---|---|
on:click={f} |
on_click=(Jsx.native f) |
oncapture:click={f} |
on_click=(Jsx.capture f) |
prop:value={v} |
value=(Jsx.prop v) |
attr:title={s} |
title=(Jsx.attr s) |
bool:hidden={b} |
hidden=(Jsx.bool b) |
on:my-event={f} |
on=(Jsx.listen "my-event" f) |
data-X={s} |
attr=(Jsx.named "data-X" s) |
The last two are for a name whose case or spelling the rule cannot keep. A wrapper left out is Solid’s default, never another namespace.
A component takes an attribute’s namespace – Jsx.attr, Jsx.bool,
Jsx.named – and passes it on to its element unchecked, as it does a data
attribute; optional, it is ?hidden=(Jsx.attr (fun () -> o)). Solid’s
server writes a plain hidden as present or absent, so hidden="until-found"
reaches a prerendered page only as attr:hidden. A handler’s and a
property’s namespaces are an element’s alone.
Data attributes
Section titled “Data attributes”A data- attribute is a Jsx.data, on an element and on a component,
which passes it on to its element, as TSX lets a component take a
hyphenated attribute. It is present, or absent while a flag is down, so a
state is in the HTML a page is prerendered with.
A component passes it on by spreading Props.others props, the props it
does not name, on its element, after its own attributes:
module Jsx = Solidtype.Jsx
let%component make ~(label : string) () = <button class_="chip" props=(Props.others props)> (fun () -> Jsx.string (label ())) </button>| TSX | OCaml |
|---|---|
data-slot="badge" |
data_slot="badge" |
data-selected={on() ? "true" : undefined} |
data_selected=(fun () -> Jsx.flag (on ())) |
data-id={id()} |
data_id=(fun () -> Jsx.data (id ())) |
Values given to a component
Section titled “Values given to a component”A literal is given as it is, and anything that may change as a thunk,
(fun () -> ...). A constant held in a name is passed as the thunk it is
read by, class_=(fun () -> item): a name alone is passed as it is, which a
component’s check takes only for a function.
An optional prop, one a component may leave out, is passed on as it is
with OCaml’s own ?: present while its option is Some, absent while it
is None, as TSX passes undefined. A component’s optional parameter is
such an option, so it passes on by its name.
| TSX | OCaml |
|---|---|
title={note()} |
?title=(fun () -> note ()) |
name={props.name} |
?name |
The compiler refuses ? on a prop that is not optional.
Spreads
Section titled “Spreads”A spread, TSX’s {...props}, is the attribute props, and so no prop is
named props:
let make (props : Props.t) = <input class_="field" props /><Dynamic component=(fun () -> Greeting.component) props />