3 Discover Shiny dependencies

3.1 Introduction

If Shiny creates HTML code for us, it is not enough to design a beautiful working app with user interactions. As shown earlier, all modern websites and apps have a lot of CSS and JavaScript under the hood. Let’s explore these elements in the following exercise.

The simplest Shiny layout is the fluidPage(). The shinyapp predefined RStudio snippet creates a basic app skeleton (type shinyapp in a new script or the console in your RStudio IDE, Figure 3.1).

shinyapp code snippet.

FIGURE 3.1: shinyapp code snippet.

We add some text inside and remove the session parameter from the server function, as we don’t need it:

library(shiny)
ui <- fluidPage(
  p("Hello World")
)

server <- function(input, output) {}
shinyApp(ui, server)

At first glance, the page only contains text. Wait … are you sure about this? Let’s run the above example and open the HTML inspector introduced in 1.3. Results are displayed on Figure 3.2.

Shiny dependencies (with {shiny} 1.6.0).

FIGURE 3.2: Shiny dependencies (with {shiny} 1.6.0).

  1. Click on “Open in Browser.”
  2. Open the HTML inspector.
  3. Locate the <head> tag.
  4. Uncollapse it and search for the script containing application/html-dependencies.
  5. List all dependencies.

According to the head section (delimited by <head></head>), Shiny has three main dependencies:

  • jQuery.
  • shiny (custom JavaScript and CSS).
  • Bootstrap (JavaScript and CSS).

As of shiny 1.6.0, json2 is not needed anymore and does not appear in the above list.

3.2 Bootstrap

According to the gitstar ranking, which is an unofficial GitHub star ranking website, Bootstrap comes at the 7th place (144563 stars) and 22th place for repositories and organization, respectively. It has been first released in 2011 and will welcome the fifth version in few months. It provides plug and play layout and interactive elements such as tabs, navigation bars, tooltips, popovers and many input (forms), which is rather convenient since it avoids writing a large amount of CSS/JavaScript that would bring more complexity. The first release of Shiny was shipped with Bootstrap 2. Shiny currently relies on Bootstrap 3 since v0.11, while a lot of efforts are being made to provide a Bootstrap 4 compatibility, essentially through the bslib R package.

One of the great advantage of using Bootstrap is the responsiveness of the design that can work either on desktop or mobile, even though advanced user likely prefer other specialized libraries like Framework7 or onsenUI to develop native looking apps, as shown in Chapter 22.

Bootstrap 3 relies on the grid layout system that allows to efficiently organize the content in row and columns. For instance the fluidRow() and column() Shiny functions leverage the Bootstrap grid to control how elements are displayed in a page.

How does Shiny attach the Bootstrap dependencies? The well known fluidPage() layout is actually hiding a lower level function, that is bootstrapPage(). The latter is also called in many other high level layout functions for instance fixedPage(), fillPage() and navbarPage(). It simply attaches bootstraplib as well as any Bootstrap compatible theme css files that one can pass with the {shinythemes} package.

As of shiny 1.6.0 end user should use the new theming tools, that is bslib, described in chapter 9.

The interested reader should have a look at the following code, inside which are defined all the Shiny Bootstrap-based layout elements, such as the well known fluidPage() wrapper.

3.3 jQuery, DOM manipulation

jQuery allows to perform DOM manipulation, that is interacting with HMTL elements, in a more user-friendly manner than with pure JavaScript. At that step, you might not be familiar with JavaScript nor jQuery. Don’t worry! Chapter 10 exposes the basics. Below is a comparison on how you would select a button HTML element with both technologies. We are sure you’ll notice how jQuery1 is more intuitive than JavaScript.

Javascript:

// select the button
var btn = document.getElementById('mybutton');
// event
btn.addEventListener('click', function() {
  alert('You clicked me!'); // action
});

jQuery:

$('#mybutton').on('click', function() {
  alert('You clicked me!');
});

Interestingly, {jquerylib} provides support for shiny by shipping the necessary content. Nowadays, many websites and frameworks (like Bootstrap 5) tend to avoid jQuery so as to gain in performance. Yet, most of Shiny’s JS code still use it and won’t be removed any time soon.

3.4 Custom dependencies

The last dependency contains custom JS and CSS code necessary for Shiny to work, that is:

  • Fine tune the layout.
  • Register input/output and handle every single input/output action. Detailed mechanisms are studied in Chapter 12 and 13.
  • Initialize and control the R/JS communication, as shown in Chapter 11.3.1.
  • Handle alerts/modals/notifications.

Chapters 10.6.3, 12, 15 and 19 showcase the most important elements of those custom files.

3.5 Exercise

In the following exercise, we consider a slightly more complex app with a slider as well as a plot output.

  1. Run the app runExample("01_hello").
  2. Open the HTML inspector.
  3. Delete the bootstrap.min.css and ion.rangeSlider.cssdependencies by removing the corresponding DOM element.
  4. What happened to the application’s UI?

To sum up, all of these libraries are necessary to make Shiny what it is! Importantly, Shiny only loads what is necessary to have. For instance, as shown above, it is only necessary to include the slider dependencies when there is at least one slider in the app, which eventually improves app performances.

In Chapter 4, we explore tools to manage HTML dependencies. In Chapters 19.4.1 and 15, we study a special case to insert dependencies at runtime.