Why you should learn Javascript to master R Shiny. And how to get started

Shiny and JavaScript

Shiny has become the status quo of building web apps/dashboards with R. A major reason of its success is that you don't need to know javascript to create basic interactive web apps.

Although the concealment of this important feature is by design and makes Shiny in the first instance easy to use, in the long run when you want to build serious and more visual appealing apps, you most likely need to utilize javascript to make most of the web framework.

Learning javascript doesn’t only benefit your shiny apps, the new acquired skill set can be applied to other R web frameworks as well, such as OpenCPU or used outside the R spectrum. Since javascript is the lingua franca of web development, it means that you can use JS to create stunning user interfaces (i.e. dashboards) for various other data (backend) languages, such as python, skala, NET, ...

How to Get Started With Javascript

A frequently heard argument against Javascript from Shiny users or R developers in general is the difficulty and the time consumption of learning Javascript. Surprised to hear this coming from developers who are familiar with a language (R) which is considered to be one of the steepest language to master. The reality is that you don't need to master javascript in depth to benefit from the language. A superficial touch, enough to let a javascript library work, would be in most cases sufficient

Furthermore, there are many JS frameworks such as jQuery (a popular framework used intensively in Shiny) that hide many complexities, making JS easier to use and to learn. jQuery is also known as the ‘code less do more’ library

Moreover, even Yihui Xie (auhor of the popular Knitr package), whose first task for RStudio was to implement the JS library datatable in Shiny, admitted in a recent blog that he didn’t have advanced JS skills when creating the package, and was frequently copying code from stackoverflow. This indicates that you don’t have to be a JS expert.

My personal experience is that you rarely need advanced JS skills to get most of a javascript library. Just like YiHui, you can use the following strategy:

  1. If you have an idea on what you want to implement in your Shiny app, search on the internet for JS libraries that can assist in achieving your goals.
  2. Having found a library that suits your need, read the documentation.
  3. After reading the documentation, look at the examples and use cases that are accompanied with the library. You can try to mimic and play around with the library on a playground such as JSFiddle

Following these 3 steps would be mostly sufficient to get started. If you need more advanced usages of the JS library, you can use stackoverflow to explore questions and answers on the JS library. Also, when you encounter errors / issues, stackoverflow is an ideal place to find solutions.

How to use Javascript within Shiny

Generally, there are 3 ways to get started with JavaScript in Shiny :

Method 1. Htmlwidgets:
Htmlwidgets basically lets you integrate libraries into the R environment, which means that in theory thousands of JavaScript libraries can be used from R. There are already some built-in widgets which you can use out of the box in Shiny, such as the popular "datatable" widget that transforms R dataframes into intereactive html tables.

HtmlWidgets can be considered as a wrapper around the JS library that you want to integrate, making the communication between a JS library and R more convenient.

Creating a htmlwidget follows the following conventions:

  • Dependencies, these are the JavaScript libraries for which you want to write an R wrapper.
  • R binding. This is the R function that you can call, and where you define the parameters, and how the widget is rendered.
  • Javascript binding, a Javascript function serving as a middle layer between the R binding (R) and the Dependencies (Javascript). The data and options are gathered from the R binding and passed to the underlying dependencies.

To have a feeling of how to implement an htmlwidget, you can have a look at the skeleton of "datatable" at github.

Method 2. Call javascript from Shiny:
A big advantage of creating an htmlwidget is that it can be used as an R package, which can be utilized outside Shiny in other R projects as well. Disadvantage is that it takes time and debugging efforts to build htmlwidgets. Another less time intensive way is calling Javascript directly from Shiny via so-called callbacks. This process entails two layers:

2a. Session$sendCustomMessage R function (sendCustomMessage) that outputs R objects to Javascript

The session$sendCustomMessage(type, object)function lives in R, and contains two parameters:

  • Type, a unique name of the callback.
  • Object, the data you want to convey.

2b. Shiny.addCustomMessageHandler. The Javascript middle layer:

Shiny.addCustomMessageHandler lives in Javascript and serves as a middle layer between R and Javascript. On the one hand it ‘receives’ the R object as passed by Session$sendCustomMessage (see a), on the other hand it passes the object to the javascript dependencies that you want to utilize in your app.

Shiny.addCustomMessageHandler(type, JavascriptFunction), contains two parameters:

  • type, the name of the callback as defined in (a).
  • JavascriptFunction is the javascript function, consuming the R object.

Fictive Example

In R we define a data.frame “df” which is subsequently conveyed to JS for each slider change event by using the session$sendCustomMessage function:

df <- data.frame(klm = c(1:100))

In JS we consume the conveyed data.frame as follows:

Shiny.addCustomMessageHandler("handler1", hello);
function hello (message){

So Shiny.addCustomMessagler lives in JS, passes the R object “df” to the hello JS function, which alerts the object on the screen.

Noteworthy is that communication between R and JavaScript takes place through JSON. Hence, calling JSON.stringify to convert the data.frame object from json to a string object.

Method 3. Send an object from Javascript to Shiny

Sending messages from Shiny to Javascript is not always sufficient, sometimes you want to enable the way around by sending objects from JS to Shiny. This entails the following two steps:

3a) Shiny.onInputChange(id, object) lives in JS and conveys JS objects to R, and contains two parameters:

  • Id = the unique id of the JS object you want to convey to R.
  • Object = JS object to be conveyed to R.

3b) Read in R ,the JS object by referencing the unique id as defined in 3a).

Fictive example:

In JS you send the following JS message object to R when an action button is hovered:

$(document).ready(function() {
  $( "#goButton" ).hover(function(){
    var message = {id: "id1", data : [1,2], nonce: Math.random()};
    Shiny.onInputChange("GetJs", message);

In R you read the JS object as follows:

observeEvent(input$GetJs, cat(“JS object received”)