6.4 Under the hood

A typical web app:

  • In the browser (front-end):
    • .html file defines the content
    • .css files define the style
    • javascript handles interactivity
  • On the server (back-end):
    • Requests received from the client
    • R performs computations based on those requests
    • Sends responses to the client

6.4.1 HTML - Hypertext markup language

To view the .html for an app

  • Open an app in the browser or Rstudio
  • “View source” / “Inspect” / Open “Developer Tools”

Typical .html structure:

<!DOCTYPE html>
<html>
  <head>
    <!-- Metadata goes here (encodings, dependencies, author ...) -->
    <meta charset="utf-8">
    <title>The page title</title>
  </head>
  <body>
    <!-- Content goes here!-->
    <h1>My Printed Title</h1>
    <p>
      A paragraph of text.
    </p>
  </body>
</html>

6.4.2 Writing HTML with shiny / htmltools

How to write .html using just R code?

The simplest shiny UI:

ui <- shiny::fluidPage()

The .html body for that UI can be viewed directly:

cat(
  as.character(ui)
)
<div class="container-fluid"></div>

To also include the ‘head’ for the .html:

cat(
  shiny:::renderPage(ui)
)
<!DOCTYPE html>
<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
  <script type="application/shiny-singletons"></script>
  <script type="application/html-dependencies">jquery[3.6.0];shiny-css[1.9.1];shiny-busy-indicators[1.9.1];shiny-javascript[1.9.1];bootstrap[3.4.1]</script>
<script src="jquery-3.6.0/jquery.min.js"></script>
<link href="shiny-css-1.9.1/shiny.min.css" rel="stylesheet" />
<link href="shiny-busy-indicators-1.9.1/busy-indicators.css" rel="stylesheet" />
<script src="shiny-javascript-1.9.1/shiny.min.js"></script>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link href="bootstrap-3.4.1/css/bootstrap.min.css" rel="stylesheet" />
<link href="bootstrap-3.4.1/accessibility/css/bootstrap-accessibility.min.css" rel="stylesheet" />
<script src="bootstrap-3.4.1/js/bootstrap.min.js"></script>
<script src="bootstrap-3.4.1/accessibility/js/bootstrap-accessibility.min.js"></script>
</head>
<body>
  <div class="container-fluid"></div>
</body>
</html>

script and link elements in the <head> = dependencies for the site

Adding bare HTML to the shiny-produced HTML

ui_with_raw_html <- shiny::fluidPage(
  # some raw html
  htmltools::HTML(r"(
    <h1>This is a heading</h1>
    <ul>
      <li>First bullet</li>
      <li>Second bullet</li>
    </ul>
    )"
  ),
  # a shiny text imput
  textInput("name", "What's your name?")
)

cat(
  as.character(ui_with_raw_html)
)
<div class="container-fluid">
  
    <h1>This is a heading</h1>
    <ul>
      <li>First bullet</li>
      <li>Second bullet</li>
    </ul>
    
  <div class="form-group shiny-input-container">
    <label class="control-label" id="name-label" for="name">What's your name?</label>
    <input id="name" type="text" class="shiny-input-text form-control" value=""/>
  </div>
</div>

Using HTML helpers:

ui_from_html_helpers <- shiny::fluidPage(
  h1("This is a heading", class = "my-class"),
  tags$ul(
    tags$li("First bullet"),
    tags$li("Second bullet")
  ),
  textInput("name", "What's your name?")
)

cat(
  as.character(ui_from_html_helpers)
)
## <div class="container-fluid">
##   <h1 class="my-class">This is a heading</h1>
##   <ul>
##     <li>First bullet</li>
##     <li>Second bullet</li>
##   </ul>
##   <div class="form-group shiny-input-container">
##     <label class="control-label" id="name-label" for="name">What's your name?</label>
##     <input id="name" type="text" class="shiny-input-text form-control" value=""/>
##   </div>
## </div>

6.4.3 CSS - Cascading Style Sheets

CSS

  • isn’t covered in the chapter (but links provided)
  • but underlies how bootstrap styles your shiny app

Much more detail at

How does the browser display a site / app?

MDN Website parsing figure

6.4.4 Using CSS to style a shiny app

A simple CSS file to set any text with “my-class” as class to red

/* ./examples/06-layout_themes_html-css_example/www/style.css */
.my-class {
  color: red
}
  • Put static files (javascript / css) in the ./www subdirectory of your app
  • Include your files using tags$link when defining the UI
  • Note: the path in the link should be “style.css” not “www/style.css”
# ./examples/06-layout_themes_html-css_example/app.R
library(shiny)

ui <- shiny::fluidPage(
  tags$link(rel = "stylesheet", type = "text/css", href = "style.css"),
  h1("This is a heading", class = "my-class"),
  textInput("name", "What's your name?")
)
server <- function(input, output, session) {}

shinyApp(ui, server)

You can write custom rules to style based on

  • html element (p, h1, …),
  • attributes
  • IDs
  • and on interactive things (eg, when the mouse hovers)