Part 1: UI Layout and Customizing

Learning Objectives

By the end of this session, you should be able to:

  • Layout your shiny app using {bslib}
  • Style your shiny app using bslib::bs_themer()
  • Style your shiny app using {thematic}

What are Shiny UIs?

  • Underneath, it’s HTML + JavaScript
  • Built on a library called Bootstrap
  • JavaScript gives us the power to update parts of the HTML dynamically

Language of the Web

Shiny

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

HTML

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

Layout Your Shiny App with {bslib}

What is {bslib}?

  • Short for BootstrapLibrary
  • Code for layout as dashboards
  • Allows for applying theming
library(bslib)
library(bsicons)
library(shiny)

Components of {bslib}

  • card
  • sidebars
  • value boxes

Layouts

  • layout_sidebar()
  • layout_column_wrap()
  • layout_columns()

Pages

  • page_sidebar()/sidebar()
  • page_navbar()/ navbar()
  • page_fillable()/layout_

Cards

library(bslib)
ui <- page(
  card({
    plotOutput("penguins")
  })
)
  • runApp("layouts/app_card.R")

page_sidebar()

library(bslib)
ui <- page_sidebar(
  sidebar = sidebar(
    selectInput("var", "Select Island",
      choices,
      selected = choices[1]
    )
  ),
  card({
    plotOutput("penguins")
  })
)
  • runApp("layouts/app_sidebar.R")

layout_column_wrap()

ui <- page_sidebar(
  sidebar = sidebar(
    selectInput("var", "Select Island", 
                choices, 
                selected = choices[1])
  ),
  card(
    layout_column_wrap(
      plotOutput("penguins"),
      plotOutput("penguins2")
    )
  )
)
  • runApp("layouts/app_layout_column.R")

Value Boxes

value_box(
  title = "I got",
  value = "99 problems",
  showcase = bs_icon("music-note-beamed"),
  p("bslib ain't one", bs_icon("emoji-smile")),
  p("hit me", bs_icon("suit-spade"))
)

I got

99 problems

bslib ain't one

hit me

Dynamic Value Box

See runApp("layouts/app_bslib_box_dynamic.R")

Laying out value boxes

page_fillable(
  layout_column_wrap(
    width = "250px",
    fill = FALSE,
    vbs[[1]], vbs[[2]]
  ),
  card(
    min_height = 200,
    plotly::plot_ly(x = rnorm(100))
  )
)

1st value

123

The 1st detail

2nd value

456

The 2nd detail

The 3rd detail

Exercise

Modify the value_box code in layouts/app_bslib_box_layout.R. Try out the following:

If you like, paste it into the Cascadia-R slack channel.

countdown::countdown(minutes = 5)
05:00

Styling Your App

Design/HTML is all about containers

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

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(
  tags$head(
    tags$style(
      HTML("
      body {
        background-color: blue;
        color: white;
      }")
    )
  ),
  # application UI
  ...
)
  • tags originates from {htmltools}, but imported with {shiny}

The good news: you don’t have to learn CSS

Style your App with {bslib} and {thematic}

  • bslib::bs_themer()
  • bslib::run_with_themer()
  • thematic::thematic_theme()

Exercise

Try running the following code below and change the bg and fg variables, as well as primary and maybe even the font. Cut and paste your bs_theme_update() code into the Slack to share your creation.

library(bslib)
run_with_themer("app_bs_themer.R")
countdown::countdown(minutes = 5)
05:00

Getting bs_themer() to work with Shiny Dashboards

runApp("layouts/_quarto_dashboard_bslib.qmd")

Boosting User Experience (UX)

Accessibility

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

Resources