Welcome

Introductions

Colin Rundel
Duke University
Barret Schloerke
Posit, PBC

Introduce yourself

We won’t go around the room, but take the next couple of minutes to introduce yourself to your neighbors.

Some suggested topics:

  • What is your name

  • Where you are coming from

  • Why you are interested in learning Shiny

03:00

Materials


Wifi: Posit Conf 2025        Password: conf2025


    pos.it/shiny-r-conf25


    github.com/posit-conf-2025/shiny-r

Schedule

Time Activity
09:00 - 10:30 Welcome & Intro
10:30 - 11:00 Coffee break
11:00 - 12:30 Reactivity
12:30 - 13:30 Lunch break
13:30 - 15:00 Dynamic & Modern UIs
15:00 - 15:30 Coffee break
15:30 - 17:00 Theming & Publishing

Housekeeping

  • Gender-neutral bathrooms - Next to Chicago A (LL2)

  • Meditation/prayer room - Chicago A (LL2)

  • Mother’s/lactation room - Chicago B (LL2)

  • Red lanyards = No photos

  • Code of Conduct - Please review carefully.

    https://posit.co/code-of-conduct.

    You can report Code of Conduct violations in person, by email, or by phone.

Asking for help (Stickies)

I’m working

I’m stuck

I’m done


I have a general question

Discord

You should have received a welcome email that contained instructions for joining the conference’s discord server.

This workshop has a channel under Workshops,

#workshop-shiny-r

This is a great place to ask questions, post resources, memes, or most anything else before, during, and after the workshop.

Computational Environment

RStudio Cloud

You can use the following link to join the workshops RStudio cloud space,

Once you have joined you can then select the shiny-r assignment,

which should then create a copy of all materials and launch a cloud session for you.

Cloud session

If everything is working you should see something similar to the following,

File organization

  • slides/ - all slides and related materials

  • demos/ - sample code for each demo

  • exercises/ - starter code for each exercise

  • exercises/solutions/ - sample solution code for each exercise

  • exercises/live/ - sample solution code we generate during the workshop, updated at the end of each session. Update via Git > Pull.

  • data/ - example data sets used in demos and exercises

Introducing Shiny

Shiny

Shiny is an R package that makes it easy to build interactive web apps straight from R. You can host standalone apps on a webpage or embed them in R Markdown documents or build dashboards. You can also extend your Shiny apps with CSS themes, htmlwidgets, and JavaScript actions.

bslib

The bslib R package provides a modern UI toolkit for Shiny and R Markdown based on Bootstrap.

Shiny + bslib

library(shiny)
library(bslib)

is now the officially recommended way to build Shiny apps.

We will be using both packages throughout the workshop, I’ll try to point out when we are using features specific to one or the other.

One of the easy ways to recognize what package is being used is that:

  • bslib functions use snake_case, and

  • shiny functions uses camelCase.

App Anatomy


Server

+


Client / Browser

+ +

App Components

library(shiny)
library(bslib)

ui = list()

server = function(input, output, session) {}

shinyApp(ui = ui, server = server)

Every Shiny app has two main components:

  • A UI (user interface) which controls how the app looks

  • and a server function which controls how the app works.

Weather data

We need some data that we will be able to interact with for our Shiny apps today. We’ve collected weather data from Meteostat for several airports around the US.

readr::read_csv(here::here("data/weather.csv"))
# A tibble: 23,376 × 17
     id name  airport_code country state region longitude latitude date      
  <dbl> <chr> <chr>        <chr>   <chr> <chr>      <dbl>    <dbl> <date>    
1 72202 Miami KMIA         US      FL    South      -80.3     25.8 2020-01-01
2 72202 Miami KMIA         US      FL    South      -80.3     25.8 2020-01-02
3 72202 Miami KMIA         US      FL    South      -80.3     25.8 2020-01-03
4 72202 Miami KMIA         US      FL    South      -80.3     25.8 2020-01-04
5 72202 Miami KMIA         US      FL    South      -80.3     25.8 2020-01-05
6 72202 Miami KMIA         US      FL    South      -80.3     25.8 2020-01-06
7 72202 Miami KMIA         US      FL    South      -80.3     25.8 2020-01-07
# ℹ 23,369 more rows
# ℹ 8 more variables: temp_avg <dbl>, temp_min <dbl>, temp_max <dbl>,
#   precip <dbl>, snow <dbl>, wind_direction <dbl>, wind_speed <dbl>,
#   air_press <dbl>

Demo 01 - Our first app

demos/demo01.R

library(tidyverse)
library(shiny)
library(bslib)

d = read_csv(here::here("data/weather.csv"))

ui = page_sidebar(
  title = "Temperatures at Major Airports",
  sidebar = sidebar(
    radioButtons(
      inputId = "name", 
      label = "Select an airport",
      choices = c(
        "Hartsfield-Jackson Atlanta",
        "Raleigh-Durham",
        "Denver",
        "Los Angeles",
        "John F. Kennedy"
      )
    ) 
  ),
  plotOutput("plot")
)

server = function(input, output, session) {
  output$plot = renderPlot({
    d |>
      filter(name %in% input$name) |>
      ggplot(aes(x=date, y=temp_avg)) +
      geom_line()
  })
}

shinyApp(ui = ui, server = server)

Your turn - Exercise 01

Open exercises/ex01.R in Posit cloud and execute it via the Run App button.

Check that you are able to successfully run the Shiny app and are able to interact with it by picking a new airport.

If everything is working try modifying the code,

  • Try adding or removing a city from radioButtons()

  • Check what happens if you add a city that is not in weather.csv

05:00

Troubleshooting

A couple of quick tips:

  • If the app can’t find the data, make sure you have opened the workshop’s RStudio project

  • If you are not using Posit cloud make sure you have the latest versions of shiny, bslib, and tidyverse installed

  • If you are stuck, ask a neighbor for help and/or raise your hand and myself or a TA will come by

UIs

Layouts

Shiny uses page layout functions as a way to specify the general organization of the UI of an app.

Our first app used a sidebar layout created with page_sidebar(). This layout consists of:

  • a title,

  • a sidebar (which usually holds inputs or extra information),

  • and then a collection of other Shiny UI elements which form the body of the app (a plot in our case).

This sidebar layout is a good place to start for most simple apps, but there are many other layouts that can be used to create more complex and interesting apps.

Shiny vs bslib layouts

Since page_sidebar() uses snake_case we can infer it is from bslib. If you’ve seen older Shiny code you may have seen fluidPage() + sidebarLayout() which come from shiny.

There are analogues of almost all of Shiny’s original page layouts in bslib, either choice is viable and will let you create a working Shiny app.

We have opted to use the bslib layouts because they are more modern and typically have a more user friendly (less nested) syntax.

UI functions are HTML

One of the neat tricks of Shiny is that the interface is just a webpage, and this can be seen by the fact that UI functions are just R functions that generate HTML.

We can run any of the following in our console and see the underlying HTML of each element.

actionButton("id", "Click me!")
selectInput("test", "Test", choices = c("A", "B", "C"), selectize = FALSE)
img(src = "shiny.png")

Input Widgets

A brief widget tour

rundel.shinyapps.io/widgets/

Your turn - Exercise 02

We’ve just seen a number of alternative input widgets, starting from the code in exercises/ex02.R try changing the radioButton() input to one of the following:

  • selectInput() with multiple = FALSE

  • selectInput() with multiple = TRUE

  • checkboxGroupInput()

What happens? Does the app still work as expected?

10:00