Fork me on GitHub

scala-js-dom


Scala-js-dom provides a nice statically typed interface to the DOM such that it can be called from Scala code without resorting to js.Dynamic. All javascript globals functions, singletons and classes are members of the org.scalajs.dom, org.scalajs.dom.html, org.scalajs.dom.svg, etc. packages. For example:

def main() = {
  import org.scalajs.dom
  dom.window.alert("Hi from Scala-js-dom")
}
Run

Will cause a javascript alert box saying `HAI` to appear. Other javascript classes and objects can be similarly accessed e.g. new dom.XMLHttpRequest() to perform a new Ajax request, dom.document to access the global document object, or html.Div to to refer to the type of a <div> element.

Usage


Add the following to your sbt build definition:

libraryDependencies += "org.scala-js" %%% "scalajs-dom" % "0.9.2"

then enjoy the types available in org.scalajs.dom. scalajs-dom 0.9.2 is built and published for Scala.js 0.6.15 and later, with Scala 2.10, 2.11, 2.12, and 2.13.0-M1.

To begin with, scala-js-dom organizes the full-list of DOM APIs into a number of buckets:

Most names have been shortened from names of the raw browser APIs, since the namespacing avoids collisions. By convention these types are imported qualified: e.g. as html.Canvas instead of directly as Canvas. There is also the dom.raw namespace which contains everything with their full, un-shortened name.

Here are some examples to get you started:

Node.appendChild

def main(div: html.Div) = {
  val child = dom.document
                 .createElement("div")

  child.textContent =
    "Hi from Scala-js-dom"

  div.appendChild(child)
}
Run
div

Node.onmousemove

def main(pre: html.Pre) = {
  pre.onmousemove = {
    (e: dom.MouseEvent) =>
      pre.textContent =
        s"""e.clientX ${e.clientX}
           |e.clientY ${e.clientY}
           |e.pageX   ${e.pageX}
           |e.pageY   ${e.pageY}
           |e.screenX ${e.screenX}
           |e.screenY ${e.screenY}
         """.stripMargin
  }
}
pre

dom.btoa

def main(in: html.Input,
         out: html.Div) = {
  in.onkeyup = { (e: dom.Event) =>
    out.textContent =
      dom.window.btoa(in.value)
  }
}

dom.localStorage

def main(in: html.Input, box: html.Div) = {
  val key = "my-key"

  in.value =
    dom.window.localStorage.getItem(key)

  in.onkeyup = { (e: dom.Event) =>
    dom.window.localStorage.setItem(
      key, in.value
    )
    box.textContent =
      "Saved! " + in.value
  }
}

dom.HTMLCanvasElement

def main(c: html.Canvas) = {
  type Ctx2D =
    dom.CanvasRenderingContext2D
  val ctx = c.getContext("2d")
             .asInstanceOf[Ctx2D]
  val w = 300
  c.width = w
  c.height = w

  ctx.strokeStyle = "red"
  ctx.lineWidth = 3
  ctx.beginPath()
  ctx.moveTo(w/3, 0)
  ctx.lineTo(w/3, w/3)
  ctx.moveTo(w*2/3, 0)
  ctx.lineTo(w*2/3, w/3)
  ctx.moveTo(w, w/2)
  ctx.arc(w/2, w/2, w/2, 0, 3.14)

  ctx.stroke()
}

dom.XMLHttpRequest

def main(pre: html.Pre) = {
  val xhr = new dom.XMLHttpRequest()
  xhr.open("GET",
    "http://api.openweathermap.org/" +
    "data/2.5/weather?q=Singapore"
  )
  xhr.onload = { (e: dom.Event) =>
    if (xhr.status == 200) {
      pre.textContent =
        xhr.responseText
    }
  }
  xhr.send()
}
Run
output

dom.Websocket

def main(in: html.Input,
         pre: html.Pre) = {
  val echo = "ws://echo.websocket.org"
  val socket = new dom.WebSocket(echo)
  socket.onmessage = {
    (e: dom.MessageEvent) =>
      pre.textContent +=
        e.data.toString
  }
  socket.onopen = { (e: dom.Event) =>
    in.onkeyup = { (e: dom.Event) =>
      socket.send(in.value)
    }
  }
}
output

Element.style

def main(div: html.Div) = {
  val colors = Seq(
    "red", "green", "blue"
  )

  val index =
    util.Random.nextInt(colors.length)

  div.style.color = colors(index)
}
Run
div

The goal of this project is to provide a thin-but-idiomatic-scala interface to modern browser APIs. In particular:

Extensions


Apart from Color, Scala-js-dom contains some useful helpers and implicit classes in org.scalajs.dom.ext that serve no purpose other than to make your use of the DOM more pleasant.

Examples include the Ajax.get and Ajax.post methods which let you avoid messing with dom.XMLHttpRequest directly, or KeyCodes which provides a nice list of the keycodes that result from pressing various keys on the keyboard.

def main(pre: html.Pre) = {
  import dom.ext.Ajax
  import scala.concurrent
              .ExecutionContext
              .Implicits
              .global
  val url =
    "http://api.openweathermap.org/" +
    "data/2.5/weather?q=Singapore"
  Ajax.get(url).onSuccess { case xhr =>
    pre.textContent = xhr.responseText
  }
}
Run
output

See also roll (live demo) and scala-js-games for an example of its use. Scala-js-fiddle also contains a pile of fun examples that demonstrate its usage. Pull requests/forks are welcome!

Contributing


Scala-js-dom is a work in progress. The current code base is a hodgepodge of auto-generated/scraped/hand-tweaked code, and is full of rough edges. If you see something that you think can be improved, feel free to send a pull request. These could include: