How to do document.createElement in ReScript

787 Views Asked by At

ReScript seems to be a better way to write JS code, but I am not able to find what should be a simple single line of docs.

How do I call functions like document.createElement()?

I tried Js.document, Dom.document, by looking at this page: https://rescript-lang.org/docs/manual/latest/api, but that code gives an error in the playground:

The value document can't be found in Js
The value document can't be found in Dom

3

There are 3 best solutions below

1
On

Since re-script is powered by React (JSX) and not standard ECMA JavaScript, I do not think you can use calls like document.createElement.

Instead, you should create the element via:

let element = <h1> {React.string("Hello World")} </h1>

This transpiles into the following:

var element = React.createElement("h1", undefined, "Hello World");

I modified the default Playground script:

module Button = {
  @react.component
  let make = (~count: int) => {
    let times = switch count {
    | 1 => "once"
    | 2 => "twice"
    | n => Belt.Int.toString(n) ++ " times"
    }
    let msg = "Click me " ++ times
    let element = <button> {React.string(msg)} </button>
    element
  }
}
3
On

To call JS functions you'll need to use ReScript's JS interop. In this case, you can use the external keyword and @val/@scope attributes to get a ReScript function that will call document.createElement when invoked:

@val @scope(("window", "document"))
external createElement: string => unit = "createElement"

createElement("div")

This will be transformed to

window.document.createElement('div');

For quick prototyping, you can also just use external and interact with the objects like RS Objects directly:

@val external document: 'a = "document"

document["createElement"]("div")

Check out the interop cheatsheet and docs for external for more common patterns.

2
On

you can use bs-webapi

open Webapi.Dom
open Belt

document
->Document.asHtmlDocument
->Option.flatMap(document => document->HtmlDocument.body)
->Option.map(body => {
  let root = document->Document.createElement("div", _)
  root->Element.setId("app")
  root->Element.appendChild(body)
})
->ignore