Design & User Experience

But … I’m not a Web Designer?

  • Wealth of packages available in the Shiny ecosystem
  • Plug-in favorite theme styles
  • Ability to go as low-level as desired with CSS and JavaScript

💡 It’s not all about you! (That’s good)

Language of the Web


dept_choices <- c("Ancient Near Easter Art", "American")
  "Select Department",
  choices = dept_choices


<div class="form-group shiny-input-container">
  <label class="control-label" id="dept-label" for="dept">
    Select Department
    <select id="dept" class="form-control">
      <option value="Ancient Near Easter Art" selected>Ancient Near Easter Art</option>
      <option value="American">American</option>

Multiple Levels of Abstraction




div(class="row", ...)


<div class="row">...</div>

Empowers users across spectrum of design experience

Cascading Style Sheets (CSS)

Set of rules that define how HTML content is presented in the browser

selector {
  property1: value;
  property2: value;

  • selector defines which elements on page to apply rule
  • property list set properties of elements to specific values

Customizing CSS in Shiny (1)

ui <- fluidPage(
      body {
        background-color: blue;
        color: white;
  # application UI
  • tags originates from {htmltools}, but imported with {shiny}

Customizing CSS in Shiny (2)

# app.R

ui <- fluidPage(
      rel = "stylesheet", 
      type = "text/css", 
      href = "custom.css"
/* www/custom.css */

body {
  background-color: blue;
  color: white;

Customizing CSS in Shiny (3)

ui <- fluidPage(
  "Art Viewer Application", 
  style = "font-family: monospace;"

Your Turn: Exercise 1

In the application ex-1/app.R, give the image display a bit of style! Visit the exercise page for more details.


(Almost) Endless Possibilities

  • Shiny UI powered by Bootstrap
  • Defaults are clean and simple
  • Revising the style for every element …

Enter {bslib}

Provides tools for customizing Bootstrap themes directly in R

  • Easy to explore theme options interactively
  • Logical parameters to most common elements for color, font, and more
  • Built upon the Sass stylesheet language to extend traditional CSS with modern features

Your Turn: Exercise 2

Building upon the app from exercise 1, use {bslib} to customize font and other theme elements!


Boosting User Experience (UX)


Prioritizing accessibility leads to better UX!

  • Keyboard navigation (without mouse)
  • Visualization color palettes accounting for vision deficiencies
  • Metadata for HTML tag attributes

Guides with {cicerone}

A convienent API to create guided tours of Shiny applications using driver.js

The {cicerone} Workflow

  1. Note the input IDs of elements for guide
  2. Use the Cicerone R6 class and step() methods to define steps
  3. Import dependencies by declaring use_cicerone() in app UI
  4. Define triggers to start guide in app server


Custom widgets and other components to enhance your Shiny application

  • Alternatives to many classic Shiny inputs wrapping specialized frameworks within Bootstrap, Material Design, and more
  • Fantastic demonstration app:

The Shiny UI Ecosystem

Choose your Widget

😀 Easy, right?

ui <- fluidPage(
  h2("My Title")
  valueBox(4024, "Total downloads")

😐 Not quite: {shiny} and {shinydashboard} use different styling toolkits under the hood

💪 {htmltools} to the Rescue

useValueBox <- function() {
  if (!requireNamespace(package = "shinydashboard")) {
    message("package 'shinydashboard' is required to run this function")
  deps <- htmltools::findDependencies(
        header = shinydashboard::dashboardHeader(),
        sidebar = shinydashboard::dashboardSidebar(),
        body = shinydashboard::dashboardBody()
  htmltools::attachDependencies(tags$div(), value = deps)

value_box <- function(...) shinydashboard::valueBox(...)

ui <- fluidPage(
  h2("My Title")
  value_box(4024, "Total downloads")

Back to {shinyWidgets}

Usage of this powerful technique in {shinyWidgets}:

Extend with JavaScript

Not Just Styling

All of Shiny’s interactivity is powered by JavaScript

  • Direct pipe to & from R process to client (browser)
  • Normal use: Everything set up for you

Foundations in place to extend Shiny’s power when desired

Shiny to JS

  type = "say-hi", 
  message = "Shiny is Fun!"

JS to Shiny

  function(msg) {
    alert('Hello user! ' + msg)

Varations underpin many community packages


Easily improve the user experience of your Shiny apps in seconds, without having to know JS

  • Enable & disable buttons
  • Show & hide elements
  • Dynamically adding and removing CSS classes
  • Click a shiny button from server side
  • Run JS scripts easily if desired

Your Turn: Exercise 3

Harness the power of custom JavaScript in the Art Viewer App!