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:
Will cause a javascript alert box saying `Hi from Scala-js-dom` 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.
Add the following to your sbt build definition:
libraryDependencies += "org.scala-js" %%% "scalajs-dom" % "2.2.0" then enjoy the types available in org.scalajs.dom. scalajs-dom 2.2.0 is built and published for Scala.js 1.5+ with Scala 2.11, 2.12, 2.13, and 3.0+.
To begin with, scala-js-dom organizes the full-list of DOM APIs into a number of buckets:
dom.html: HTML element APIsdom.svg: SVG element APIsdom.idb: IndexedDB APIsdom.css: CSS APIsdom: Miscellanious, unclassified APIs 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:
def main(div: html.Div) = { val child = dom.document.createElement("div") child.textContent = "Hi from Scala-js-dom" div.appendChild(child) }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 } }Hover this box!
def main(in: html.Input, out: html.Div) = { in.onkeyup = { (e: dom.Event) => out.textContent = dom.window.btoa(in.value) } }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 } }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() }def main(pre: html.Pre) = { import scala.concurrent .ExecutionContext .Implicits .global import js.Thenable.Implicits._ val url = "https://www.boredapi.com/api/activity" val responseText = for { response <- dom.fetch(url) text <- response.text() } yield { text } for (text <- responseText) pre.textContent = text }output
def main(in: html.Input, pre: html.Pre) = { val echo = "wss://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
def main(div: html.Div) = { val colors = Seq( "red", "green", "blue" ) val index = util.Random.nextInt(colors.length) div.style.color = colors(index) }The goal of this project is to provide a thin-but-idiomatic-scala interface to modern browser APIs. In particular:
instanceof in javascript) should be a Scala class; any other interface which isn't a Javascript type should be a trait.def, and not-directly-instantiable classes should have private constructors. The DOM API is always evolving, and scala-js-dom is a hodgepodge of auto-generated/scraped/hand-tweaked code full of rough edges. If you see something that you think can be improved, feel free to send a pull request. These could include: