PPX syntax extension
The js_of_ocaml-ppx package provides syntax for working with JavaScript values from OCaml. This page is a syntax reference; see JavaScript interop for conceptual background on types, conversions, and when to use each approach.
Installation ¶
opam install js_of_ocaml-ppx
With dune, add the preprocessor to your library or executable:
(library (name mylib) (preprocess (pps js_of_ocaml-ppx)))
Quick reference ¶
| Syntax | Description | Example |
|---|---|---|
| obj##.prop | Get property | element##.innerHTML |
| obj##.prop := v | Set property | element##.innerHTML := Js.string "Hi" |
| obj##meth args | Call method | console##log (Js.string "Hi") |
| new%js constr args | Call constructor | new%js array_constr 10 |
| object%js ... end | Create object literal | See below |
Getting properties ¶
Use ##. (with a dot) to access a property:
(* Get the document title *)
let title = Dom_html.document##.title
(* Get element dimensions *)
let width = element##.clientWidth
let height = element##.clientHeight
(* Get nested properties *)
let href = Dom_html.window##.location##.hrefTyping rule
obj : <prop : t Js.readonly_prop> Js.t
--------------------------------------
obj##.prop : t
Setting properties ¶
Use ##. with := to set a property:
(* Set the document title *)
Dom_html.document##.title := Js.string "New Title"
(* Set element style *)
element##.style##.color := Js.string "red"
element##.style##.display := Js.string "none"
(* Set event handler *)
button##.onclick := Dom_html.handler (fun _ ->
Console.console##log (Js.string "Clicked!");
Js._true)Typing rule
obj : <prop : t Js.writeonly_prop> Js.t value : t ----------------------------------------- obj##.prop := value : unit
Calling methods ¶
Use ## (without a dot) to call a method:
(* Console logging *)
Console.console##log (Js.string "Hello")
Console.console##warn (Js.string "Warning!")
(* DOM methods *)
let element = Dom_html.document##getElementById (Js.string "myId")
Dom_html.document##.body##appendChild element
(* String methods *)
let upper = js_string##toUpperCase
let sub = js_string##substring 0 5
(* Array methods *)
js_array##push item
js_array##forEach (Js.wrap_callback (fun x _idx _arr ->
Console.console##log x))Method chaining
For easier chaining, you can wrap the method call in parentheses:
(* These are equivalent *)
let result = obj##meth1##meth2##meth3
let result = obj##(meth1)##(meth2)##(meth3)
(* Useful when methods have arguments *)
let result = str##(split (Js.string ","))##(join (Js.string ";"))Typing rule
obj : <meth : t1 -> t2 -> ... -> tn -> u Js.meth> Js.t
args : t1, t2, ..., tn
-------------------------------------------------------
obj##meth args : u
Note: Partial application is not allowed. You must provide all arguments.
Using constructors ¶
Use new%js to call JavaScript constructors:
(* Create a Date *)
let date_constr = Js.Unsafe.global##._Date
let now = new%js date_constr
let specific = new%js date_constr 2024 0 15 (* Jan 15, 2024 *)
(* Create a RegExp *)
let regexp_constr = Js.Unsafe.global##._RegExp
let pattern = new%js regexp_constr (Js.string "\\d+") (Js.string "g")
(* Create an Array with size *)
let array_constr = Js.Unsafe.global##._Array
let arr = new%js array_constr 10Non-identifier constructors
When the constructor is not a simple identifier, bind it first:
let constr = (Js.Unsafe.global##.SomeLib)##._SomeClass in
let obj = new%js constr arg1 arg2Typing rule
constr : (t1 -> ... -> tn -> u Js.t) Js.constr
args : t1, ..., tn
----------------------------------------------
new%js constr args : u Js.t
Creating object literals ¶
Use object%js ... end to create JavaScript object literals:
(* Simple object *)
let point = object%js
val x = 10
val y = 20
end
(* Object with methods *)
let counter = object%js (self)
val mutable count = 0
method increment = self##.count := self##.count + 1
method get = self##.count
end
(* Configuration object *)
let config = object%js
val url = Js.string "https://api.example.com"
val timeout = 5000
val mutable retries = 3
endProperty attributes
Control property access with attributes:
object%js
val readonly_prop = 42 (* read-only by default *)
val also_readonly = 42 [@@readonly] (* explicit read-only *)
val mutable readwrite = 42 (* read/write with mutable *)
val also_readwrite = 42 [@@readwrite] (* explicit read/write *)
val writeonly = 42 [@@writeonly] (* write-only *)
val optional = Js.undefined [@@optdef] (* optional/undefined *)
end| Declaration | Property type | Can read | Can write |
|---|---|---|---|
| val x = v | readonly_prop | Yes | No |
| val mutable x = v | prop | Yes | Yes |
| val x = v [@@readonly] | readonly_prop | Yes | No |
| val x = v [@@readwrite] | prop | Yes | Yes |
| val x = v [@@writeonly] | writeonly_prop | No | Yes |
| val x = v [@@optdef] | optdef_prop | Yes (Js.Optdef) | Yes |
Using self
The identifier in parentheses binds to JavaScript's this:
let obj = object%js (self)
val mutable x = 0
method setX v = self##.x := v
method getX = self##.x
method double = self##setX (self##.x * 2)
endGenerated type
The object literal:
object%js (self)
val x = 3
val mutable y = 4
method add dx dy =
self##.x + self##.y + dx + dy
endHas the type:
< x : int Js.readonly_prop;
y : int Js.prop;
add : int -> int -> int Js.meth > Js.tSee also
- JavaScript interop - Concepts: type conversions, null/undefined, callbacks, bindings
- Js - Full API reference