= JavaScript interoperability

This page explains how to interact with JavaScript from OCaml using
the Js_of_ocaml library.

==@@id="introduction"@@ Introduction

OCaml and JavaScript represent values differently, for example:
* OCaml strings are sequence of bytes; JavaScript strings are UTF-16
* OCaml booleans are integers (0/1); JavaScript has distinct {{{true}}}/{{{false}}}
* OCaml arrays have a tag element; JavaScript arrays don't
* OCaml objects don't map to JavaScript objects

Js_of_ocaml (the lib) provides a typed interface to bridge these differences safely.

=== Alternatives

Other libraries for JavaScript interop:
* [[https://erratique.ch/software/brr|Brr]] — Alternative browser API bindings with a different design
* [[https://github.com/LexiFi/gen_js_api|gen_js_api]] — Generates bindings from TypeScript definitions

==@@id="js-t"@@ Core concept: {{{'a Js.t}}}

All JavaScript values have type {{{'a Js.t}}}
where the phantom type parameter {{{'a}}} encodes the shape of the JavaScript
value:

For example, {{{Js.js_string Js.t}}} represents a JavaScript string, and
{{{< length : int Js.readonly_prop > Js.t}}} represents an object with a
{{{length}}} property.

To work with these values (access properties, call methods), you need the
<<a_manual chapter="ppx"|PPX syntax extension>> which provides operators like
{{{##.}}} and {{{##}}}.

==@@id="conversions"@@ Conversions

OCaml and JavaScript represent basic types differently (see
<<a_manual chapter="runtime-representation"|runtime representation>>). For example,
OCaml strings are byte sequences while JavaScript strings are UTF-16. When passing
values between OCaml and JavaScript code, you must convert them explicitly.

The conversion functions follow a consistent naming pattern:
* **{{{Js.xxx}}}** converts OCaml to JavaScript (e.g., {{{Js.string}}}, {{{Js.bool}}}, {{{Js.array}}})
* **{{{Js.to_xxx}}}** converts JavaScript to OCaml (e.g., {{{Js.to_string}}}, {{{Js.to_bool}}}, {{{Js.to_array}}})

**When do you need to convert?**
* Passing OCaml values to JavaScript functions or properties
* Reading JavaScript values back into OCaml
* Working with DOM APIs (which use JavaScript types)

**Exception**: OCaml integers can be used directly—no conversion needed.

=== Summary

|= OCaml type |= JS type |= OCaml -> JS |= JS -> OCaml |
| {{{string}}} | String | <<a_api subproject="js_of_ocaml" text="Js.string"|val Js_of_ocaml.Js.string>> | <<a_api subproject="js_of_ocaml" text="Js.to_string"|val Js_of_ocaml.Js.to_string>> |
| {{{string}}} (bytes) | String | <<a_api subproject="js_of_ocaml" text="Js.bytestring"|val Js_of_ocaml.Js.bytestring>> | <<a_api subproject="js_of_ocaml" text="Js.to_bytestring"|val Js_of_ocaml.Js.to_bytestring>> |
| {{{bool}}} | Boolean | <<a_api subproject="js_of_ocaml" text="Js.bool"|val Js_of_ocaml.Js.bool>> | <<a_api subproject="js_of_ocaml" text="Js.to_bool"|val Js_of_ocaml.Js.to_bool>> |
| {{{int}}} | Number | (direct) | (direct) |
| {{{float}}} | Number | <<a_api subproject="js_of_ocaml" text="Js.float"|val Js_of_ocaml.Js.float>> | <<a_api subproject="js_of_ocaml" text="Js.to_float"|val Js_of_ocaml.Js.to_float>> |
| {{{'a array}}} | Array | <<a_api subproject="js_of_ocaml" text="Js.array"|val Js_of_ocaml.Js.array>> | <<a_api subproject="js_of_ocaml" text="Js.to_array"|val Js_of_ocaml.Js.to_array>> |

=== Strings

OCaml strings are byte arrays; JavaScript strings are UTF-16.

<<code language="ocaml"|
(* OCaml string -> JS string *)
let js_str : Js.js_string Js.t = Js.string "Hello"

(* JS string -> OCaml string *)
let ocaml_str : string = Js.to_string js_str
>>

For binary data (bytes 0-255), use <<a_api subproject="js_of_ocaml" text="Js.bytestring"|val Js_of_ocaml.Js.bytestring>> and <<a_api subproject="js_of_ocaml" text="Js.to_bytestring"|val Js_of_ocaml.Js.to_bytestring>>:

<<code language="ocaml"|
let js_bytes = Js.bytestring "\x00\x01\x02"
let ocaml_bytes = Js.to_bytestring js_bytes
>>

=== Booleans

OCaml booleans are encoded as 0 and 1, not JavaScript's {{{true}}} and {{{false}}}.

<<code language="ocaml"|
let js_true : bool Js.t = Js._true        (* or Js.bool true *)
let js_false : bool Js.t = Js._false      (* or Js.bool false *)
let ocaml_bool : bool = Js.to_bool js_true
>>

=== Numbers

OCaml integers can be used directly. Floats need conversion.

<<code language="ocaml"|
(* Floats need conversion *)
let js_num : Js.number Js.t = Js.float 3.14
let ocaml_float : float = Js.to_float js_num
>>

=== Arrays

<<code language="ocaml"|
(* OCaml array -> JS array *)
let js_arr : int Js.js_array Js.t = Js.array [| 1; 2; 3 |]

(* JS array -> OCaml array *)
let ocaml_arr : int array = Js.to_array js_arr
>>

==@@id="describing-objects"@@ Describing JS objects

To call methods or access properties on a JavaScript object, you need to
tell OCaml what shape the object has. This is done using OCaml class types,
where each {{{method}}} declaration describes either a JavaScript property
or method.

There are two ways to write these types:

**Inline (anonymous) types** — useful for one-off or simple cases:
{{{
< field1 : type1; field2 : type2; ... > Js.t
}}}

**Named class types** — better for reusable or complex interfaces:
<<code language="ocaml"|
class type myObject = object
  method field1 : type1
  method field2 : type2
end

(* Use as: myObject Js.t *)
>>

For instance, a JavaScript object with a {{{data}}} property and an
{{{appendData}}} method would have type:
{{{
< data : Js.js_string Js.t Js.prop;
  appendData : Js.js_string Js.t -> unit Js.meth > Js.t
}}}

=== Property types

|= Type |= Description |
| {{{'a Js.readonly_prop}}} | Read-only property |
| {{{'a Js.writeonly_prop}}} | Write-only property |
| {{{'a Js.prop}}} | Read/write property |
| {{{t1 -> ... -> tn -> t Js.meth}}} | Method taking n arguments |
| {{{'a Js.optdef_prop}}} | Optional property (may be {{{undefined}}}) |

The <<a_manual chapter="ppx"|PPX syntax>> rely on these info to provide type safe access to properties and method.

=== Example

Given a JavaScript object:
<<code language="javascript"|
{
  name: "example",           // read-only string
  count: 42,                 // read-write number
  greet: function(x) { ... } // method
}
>>

Its type could be {{{myObj Js.t}}}:
<<code language="ocaml"|
class type myObj = object
  method name : Js.js_string Js.t Js.readonly_prop
  method count : int Js.prop
  method greet : Js.js_string Js.t -> unit Js.meth
end
>>

=== Method and property name mangling

When accessing a field using the {{{##.}}}/{{{##}}} syntax, the field name is transformed by:
# Removing a leading underscore (if present)
# Removing all characters starting from the last underscore

This enables:
* **Capitalized names**: {{{_Foo}}} refers to JavaScript's {{{Foo}}}
* **Reserved ocaml keywords**: {{{_type}}} refers to JavaScript's {{{type}}}
* **Method overloading**: {{{foo_int}}} and {{{foo_string}}} both refer to {{{foo}}}

**Warning**: This mangling is a common source of bugs. If you write
{{{obj##.some_property}}}, it accesses the JavaScript property {{{some}}} (not
{{{some_property}}}). To access {{{some_property}}}, use {{{obj##._some_property_}}}
or {{{obj##.some_property_}}}.

==== Examples

<<code language="ocaml"|
class type canvas = object
  (* All three refer to the same JS method: drawImage *)
  method drawImage :
      imageElement Js.t -> int -> int -> unit Js.meth
  method drawImage_withSize :
      imageElement Js.t -> int -> int -> int -> int -> unit Js.meth
  method drawImage_fromCanvas :
      canvasElement Js.t -> int -> int -> unit Js.meth
end
>>

==== Full naming rules

<<code language="ocaml"|
class type example = object
  (* All of these refer to JS field [meth] *)
  method meth : ..
  method meth_int : ..
  method _meth_ : ..
  method _meth_aa : ..

  (* All of these refer to JS field [meth_a] *)
  method meth_a_int : ..
  method _meth_a_ : ..
  method _meth_a_b : ..

  (* Refer to [Meth] (capitalized) *)
  method _Meth : ..

  (* Refer to [_meth] (leading underscore in JS) *)
  method __meth : ..

  (* Refer to [_] *)
  method __ : ..
end
>>

=== Binding constants from a class

For JavaScript constants like {{{SomeLib.SomeClass.VALUE_A}}}:

<<code language="ocaml"|
(* Type definition *)
class type someClass = object
  method _VALUE_A_ : int Js.readonly_prop
  method _VALUE_B_ : int Js.readonly_prop
end

(* Get the class object *)
let someClass : someClass Js.t =
  (Js.Unsafe.js_expr "SomeLib")##._SomeClass

(* Access constants *)
let value_a = someClass##._VALUE_A_
>>

==@@id="accessing-values"@@ Accessing JavaScript values

Once you have described a JavaScript object's type, use the
<<a_manual chapter="ppx"|PPX syntax>> to access its properties and methods:

* {{{obj##.prop}}} — read a property
* {{{obj##.prop := v}}} — write a property
* {{{obj##meth args}}} — call a method

=== Global variables

Global JavaScript variables are properties of the global object. Use
<<a_api subproject="js_of_ocaml" text="Js.Unsafe.global"|val Js_of_ocaml.Js.Unsafe.global>> to access them ({{{window}}} in browsers,
{{{globalThis}}} in Node.js):

<<code language="ocaml"|
(* Access document *)
let doc : Dom_html.document Js.t = Js.Unsafe.global##.document

(* Read and write a custom global *)
let get_config () : config Js.t = Js.Unsafe.global##.myAppConfig
let set_config (x : config Js.t) = Js.Unsafe.global##.myAppConfig := x
>>

You can also use <<a_api subproject="js_of_ocaml" text="Js.Unsafe.js_expr"|val Js_of_ocaml.Js.Unsafe.js_expr>> for any JavaScript expression:
<<code language="ocaml"|
let v = (Js.Unsafe.js_expr "window")##.document
>>

Be careful: both <<a_api subproject="js_of_ocaml" text="Js.Unsafe.global"|val Js_of_ocaml.Js.Unsafe.global>> and <<a_api subproject="js_of_ocaml" text="Js.Unsafe.js_expr"|val Js_of_ocaml.Js.Unsafe.js_expr>> are untyped.
Verify the library documentation before writing type annotations.

=== Untyped property access

When a property is missing from the OCaml interface, use
<<a_api subproject="js_of_ocaml" text="Js.Unsafe.coerce"|val Js_of_ocaml.Js.Unsafe.coerce>> for untyped access:

<<code language="ocaml"|
(* Read a property *)
let value = (Js.Unsafe.coerce obj)##.someProp

(* Write a property *)
(Js.Unsafe.coerce obj)##.someProp := v
>>

==@@id="null-undefined"@@ Handling null and undefined

JavaScript has two "missing value" types: {{{null}}} and {{{undefined}}}.
Js_of_ocaml represents these with distinct types.

=== Js.Opt for nullable values ({{{null}}})

Use <<a_api subproject="js_of_ocaml" text="Js.Opt"|module Js_of_ocaml.Js.Opt>> for values that may be {{{null}}} (e.g., DOM methods that
return {{{null}}} when an element is not found):

<<code language="ocaml"|
(* Check if null *)
let is_present = Js.Opt.test value

(* Convert to OCaml option *)
let opt : element Js.t option = Js.Opt.to_option value

(* Handle both cases *)
let result = Js.Opt.case value
  (fun () -> (* null *) "not found")
  (fun v -> (* has value *) process v)

(* Get value or raise exception *)
let v = Js.Opt.get value (fun () -> failwith "was null")

(* Create nullable values *)
let some_val : element Js.t Js.opt = Js.some element
let null_val : element Js.t Js.opt = Js.null
>>

=== Js.Optdef for optional values ({{{undefined}}})

Use <<a_api subproject="js_of_ocaml" text="Js.Optdef"|module Js_of_ocaml.Js.Optdef>> for values that may be {{{undefined}}} (e.g., optional
object properties, array access beyond bounds):

<<code language="ocaml"|
(* Check if defined *)
let is_defined = Js.Optdef.test value

(* Convert to OCaml option *)
let opt : config Js.t option = Js.Optdef.to_option value

(* Handle both cases *)
let result = Js.Optdef.case value
  (fun () -> (* undefined *) default_config)
  (fun v -> (* defined *) v)

(* Create optdef values *)
let def_val : int Js.optdef = Js.def 42
let undef_val : int Js.optdef = Js.undefined
>>

==@@id="calling-functions"@@ Calling JavaScript functions

OCaml and Javascript do not follow the same calling convention. In
OCaml, functions can be partially applied, returning a function
closure. In Javascript, when only some of the parameters are passed,
the others are set to the undefined value. As a consequence, it is not
possible to call a Javascript function from OCaml as if it was an
OCaml function, and conversely.

There are three ways to call JavaScript functions, depending on how {{{this}}}
should be bound.

At the moment, there is no syntactic sugar for calling Javascript functions.

=== Standalone functions with {{{fun_call}}}

Use <<a_api subproject="js_of_ocaml" text="Js.Unsafe.fun_call"|val Js_of_ocaml.Js.Unsafe.fun_call>> for functions where {{{this}}} doesn't matter:

<<code language="ocaml"|
(* Equivalent to: decodeURI(s) *)
let decodeURI (s : Js.js_string Js.t) : Js.js_string Js.t =
  Js.Unsafe.fun_call
    (Js.Unsafe.js_expr "decodeURI")
    [| Js.Unsafe.inject s |]

(* Equivalent to: parseInt(s, 10) *)
let parseInt (s : Js.js_string Js.t) : int =
  Js.Unsafe.fun_call
    (Js.Unsafe.js_expr "parseInt")
    [| Js.Unsafe.inject s; Js.Unsafe.inject 10 |]
>>

=== Methods with {{{meth_call}}}

Use <<a_api subproject="js_of_ocaml" text="Js.Unsafe.meth_call"|val Js_of_ocaml.Js.Unsafe.meth_call>> to call a method on an object ({{{this}}} is
bound to the object):

<<code language="ocaml"|
(* Equivalent to: arr.slice(1, 3) *)
let slice arr start stop =
  Js.Unsafe.meth_call arr "slice"
    [| Js.Unsafe.inject start; Js.Unsafe.inject stop |]
>>

=== Functions with explicit {{{this}}} binding

Use <<a_api subproject="js_of_ocaml" text="Js.Unsafe.call"|val Js_of_ocaml.Js.Unsafe.call>> when you need to explicitly set {{{this}}}:

<<code language="ocaml"|
(* Equivalent to: func.call(thisArg, arg1, arg2) *)
let result =
  Js.Unsafe.call func thisArg [| Js.Unsafe.inject arg1; Js.Unsafe.inject arg2 |]
>>

=== Calling runtime primitives

For JavaScript functions declared in runtime files (with {{{//Provides:}}}),
you can use OCaml {{{external}}} declarations:

<<code language="ocaml"|
external my_primitive : int -> int -> int = "my_js_function"
>>

This calls the JavaScript function {{{my_js_function}}} directly, without the
overhead of {{{Js.Unsafe}}} wrappers. See <<a_manual chapter="linker" fragment="writing-primitives"|writing JavaScript primitives>>
for how to define such functions.

==@@id="callbacks"@@ Passing OCaml functions to JavaScript

When JavaScript code needs to call back into OCaml (e.g., event handlers,
async callbacks), you must wrap OCaml functions appropriately.

=== Basic callbacks with {{{Js.wrap_callback}}}

<<code language="ocaml"|
(* setTimeout example *)
let set_timeout f ms =
  Js.Unsafe.global##setTimeout
    (Js.wrap_callback f)
    ms

let () = set_timeout (fun () -> print_endline "Hello!") 1000
>>

<<a_api subproject="js_of_ocaml" text="Js.wrap_callback"|val Js_of_ocaml.Js.wrap_callback>> handles partial application: if JavaScript
calls the function with fewer arguments than expected, the result is a
partially applied function.

=== Callbacks with {{{this}}} binding

Use <<a_api subproject="js_of_ocaml" text="Js.wrap_meth_callback"|val Js_of_ocaml.Js.wrap_meth_callback>> when the callback needs access to {{{this}}}:

<<code language="ocaml"|
(* The first parameter receives the 'this' value *)
let callback = Js.wrap_meth_callback (fun this event ->
  let target : Dom_html.element Js.t = this in
  (* ... handle event ... *)
  Js._true)
>>

=== DOM event handlers

For DOM events, use <<a_api subproject="js_of_ocaml" text="Dom_html.handler"|val Js_of_ocaml.Dom_html.handler>> which wraps the function
and handles the return value ({{{Js._false}}} prevents the default action):

<<code language="ocaml"|
let handler = Dom_html.handler (fun event ->
  Dom_html.window##alert (Js.string "Clicked!");
  Js._true)

button##.onclick := handler
>>

For handlers that need access to {{{this}}}, use <<a_api subproject="js_of_ocaml" text="Dom.full_handler"|val Js_of_ocaml.Dom.full_handler>>:

<<code language="ocaml"|
let handler = Dom.full_handler (fun this event ->
  let element : Dom_html.element Js.t = this in
  (* ... *)
  Js._true)
>>

=== Strict arity callbacks

For performance-critical code, or when you don't need partial application,
use <<a_api subproject="js_of_ocaml" text="Js.Unsafe.callback"|val Js_of_ocaml.Js.Unsafe.callback>>:

<<code language="ocaml"|
(* Strict callback - missing args become undefined, extra args are lost *)
let strict_cb = Js.Unsafe.callback (fun x y -> x + y)

(* Explicit arity - ensures exactly 2 arguments *)
let arity_cb = Js.Unsafe.callback_with_arity 2 (fun x y -> x + y)
>>

=== Callbacks with variable arguments

Use <<a_api subproject="js_of_ocaml" text="Js.Unsafe.callback_with_arguments"|val Js_of_ocaml.Js.Unsafe.callback_with_arguments>> when the callback receives a
variable number of arguments:

<<code language="ocaml"|
let varargs_cb = Js.Unsafe.callback_with_arguments (fun args ->
  let len = args##.length in
  Printf.printf "Called with %d arguments\n" len)
>>

==@@id="feature-detection"@@ Feature detection

JavaScript APIs vary across browsers. Use <<a_api subproject="js_of_ocaml" text="Js.Optdef"|module Js_of_ocaml.Js.Optdef>>
to check for optional features:

<<code language="ocaml"|
let supports_fetch () =
  Js.Optdef.test Js.Unsafe.global##.fetch

let supports_local_storage () =
  Js.Optdef.test Js.Unsafe.global##.localStorage

(* Safely access optional members *)
let get_optional_method obj =
  Js.Optdef.to_option (Js.Unsafe.coerce obj)##.someMethod
>>

==@@id="union-types"@@ Union types

JavaScript APIs often use union types (e.g., {{{string | Node}}}). Since OCaml
requires a single type, use an opaque type with runtime checking.

=== Using {{{instanceof}}} for object types

<<code language="ocaml"|
(* Opaque type representing the union: Element | Text *)
type element_or_text

class type container = object
  method child : element_or_text Js.t Js.prop
end

(* Cast using instanceof *)
let as_element (x : element_or_text Js.t) : Dom.element Js.t Js.opt =
  if Js.instanceof x (Js.Unsafe.global##._Element)
  then Js.some (Js.Unsafe.coerce x)
  else Js.null
>>

=== Using {{{typeof}}} for primitive types

<<code language="ocaml"|
type string_or_number

let as_string (x : string_or_number Js.t) : Js.js_string Js.t Js.opt =
  if Js.typeof x = Js.string "string"
  then Js.some (Js.Unsafe.coerce x)
  else Js.null
>>

=== Converting to OCaml variants

<<code language="ocaml"|
type child =
  | Element of Dom.element Js.t
  | Text of Dom.text Js.t

let classify_child (x : element_or_text Js.t) : child =
  if Js.instanceof x (Js.Unsafe.global##._Element)
  then Element (Js.Unsafe.coerce x)
  else Text (Js.Unsafe.coerce x)

(* Now use pattern matching *)
let handle container =
  match classify_child container##.child with
  | Element e -> (* work with element *)
  | Text t -> (* work with text node *)
>>

==@@id="json"@@ JSON serialization

The <<a_api subproject="js_of_ocaml" text="Json"|module Js_of_ocaml.Json>> module
provides serialization between OCaml values and JSON strings. The
deserialization is unsafe in the same way the OCaml
Marshal.from_string function is.

<<code language="ocaml"|
(* OCaml value -> JSON string *)
let json : Js.js_string Js.t = Json.output value

(* JSON string -> OCaml value (unsafe, like Marshal) *)
let value : 'a = Json.unsafe_input json
>>

For type-safe JSON handling, use <<a_manual chapter="ppx-deriving"|ppx_deriving_json>>.

==@@id="runtime-values"@@ Accessing runtime values

JavaScript values declared with {{{//Provides:}}} in runtime files can be
accessed from OCaml. There are two approaches depending on whether you're
accessing a function or a non-function value.

See <<a_manual chapter="linker" fragment="writing-primitives"|writing JavaScript primitives>>
for more about the {{{//Provides:}}} syntax.

=== Functions: use {{{external}}}

For JavaScript **functions**, use OCaml's {{{external}}} declaration:

<<code language="javascript"|
//Provides: my_add
function my_add(x, y) { return x + y; }
>>

<<code language="ocaml"|
external my_add : int -> int -> int = "my_add"

let result = my_add 1 2  (* calls the JS function directly *)
>>

This is efficient and integrates naturally with OCaml code.

=== Non-function values: use {{{runtime_value}}}

For JavaScript **objects, constants, or other non-function values**, use
<<a_api subproject="js_of_ocaml" text="Js.runtime_value"|val Js_of_ocaml.Js.runtime_value>>:

<<code language="javascript"|
//Provides: myConfig
var myConfig = { debug: true, version: 42 };
>>

<<code language="ocaml"|
let config : < debug : bool Js.t Js.prop; version : int Js.prop > Js.t =
  Js.runtime_value "myConfig"
>>

**Important**: The argument must be a string literal, not a variable.

== See also

* <<a_manual chapter="ppx"|PPX syntax>> - Syntax reference: {{{##.}}}, {{{##}}}, {{{new%js}}}, {{{object%js}}}
* <<a_manual chapter="rev-bindings"|Exporting to JavaScript>> - Make OCaml code callable from JavaScript
* <<a_api subproject="js_of_ocaml" text="Js"|module Js_of_ocaml.Js>> - Core JavaScript bindings
* <<a_api subproject="js_of_ocaml" text="Dom_html"|module Js_of_ocaml.Dom_html>> - HTML DOM bindings