Shiny Exercises in R: 30 Practice Problems

Thirty practice problems on Shiny: UI elements, server logic, reactivity, inputs, outputs, modules, deployment. Solutions hidden.

library(shiny)
library(ggplot2)
library(dplyr)
library(rsconnect)

Section 1. UI basics (8 problems)

Exercise 1.1: Minimal app

Difficulty: Beginner.

Show solution
ui <- fluidPage("Hello world")
server <- function(input, output) {}
# shinyApp(ui, server)

Exercise 1.2: title + page layout

Difficulty: Beginner.

Show solution
ui <- fluidPage(titlePanel("Demo"), sidebarLayout(sidebarPanel("side"), mainPanel("main")))

Exercise 1.3: textInput

Difficulty: Beginner.

Show solution
ui <- fluidPage(textInput("name", "Name:"), textOutput("hello"))
server <- function(input, output) {
  output$hello <- renderText(paste("Hello", input$name))
}

Exercise 1.4: numericInput

Difficulty: Beginner.

Show solution
ui <- fluidPage(numericInput("n", "n:", value = 10),
                textOutput("sq"))
server <- function(input, output) {
  output$sq <- renderText(input$n^2)
}

Exercise 1.5: sliderInput

Difficulty: Beginner.

Show solution
ui <- fluidPage(sliderInput("x", "x:", min = 0, max = 100, value = 50),
                textOutput("y"))
server <- function(input, output) output$y <- renderText(input$x * 2)

Exercise 1.6: selectInput

Difficulty: Beginner.

Show solution
ui <- fluidPage(selectInput("c", "Choose:", choices = c("a","b","c")),
                textOutput("o"))
server <- function(input, output) output$o <- renderText(input$c)

Exercise 1.7: actionButton

Difficulty: Intermediate.

Show solution
ui <- fluidPage(actionButton("go", "Go"), textOutput("o"))
server <- function(input, output) {
  output$o <- renderText({ input$go; format(Sys.time()) })
}

Exercise 1.8: checkboxGroupInput

Difficulty: Intermediate.

Show solution
ui <- fluidPage(checkboxGroupInput("opts", "Options", c("a","b","c")),
                textOutput("o"))
server <- function(input, output) output$o <- renderText(paste(input$opts, collapse = ","))

Section 2. Outputs (6 problems)

Exercise 2.1: textOutput

Difficulty: Beginner.

Show solution
ui <- fluidPage(textOutput("t"))
server <- function(input, output) output$t <- renderText("hello")

Exercise 2.2: tableOutput

Difficulty: Beginner.

Show solution
ui <- fluidPage(tableOutput("tbl"))
server <- function(input, output) output$tbl <- renderTable(head(mtcars))

Exercise 2.3: plotOutput

Difficulty: Intermediate.

Show solution
ui <- fluidPage(plotOutput("p"))
server <- function(input, output) {
  output$p <- renderPlot(plot(mtcars$wt, mtcars$mpg))
}

Exercise 2.4: ggplot output

Difficulty: Intermediate.

Show solution
ui <- fluidPage(plotOutput("p"))
server <- function(input, output) {
  output$p <- renderPlot(ggplot(mtcars, aes(wt, mpg)) + geom_point())
}

Exercise 2.5: dataTableOutput (DT)

Difficulty: Intermediate.

Show solution
ui <- fluidPage(DT::DTOutput("tbl"))
server <- function(input, output) output$tbl <- DT::renderDT(mtcars)

Exercise 2.6: verbatimTextOutput

Difficulty: Intermediate.

Show solution
ui <- fluidPage(verbatimTextOutput("o"))
server <- function(input, output) output$o <- renderPrint(summary(mtcars))

Section 3. Reactivity (6 problems)

Exercise 3.1: reactive expression

Difficulty: Intermediate.

Show solution
ui <- fluidPage(numericInput("n", "n:", 10), textOutput("sq"))
server <- function(input, output) {
  squared <- reactive(input$n^2)
  output$sq <- renderText(squared())
}

Exercise 3.2: observeEvent

Difficulty: Intermediate.

Show solution
ui <- fluidPage(actionButton("go", "Go"))
server <- function(input, output) {
  observeEvent(input$go, message("clicked"))
}

Exercise 3.3: eventReactive

Difficulty: Advanced.

Show solution
ui <- fluidPage(numericInput("n", "n:", 10), actionButton("go","Go"), textOutput("o"))
server <- function(input, output) {
  v <- eventReactive(input$go, input$n^2)
  output$o <- renderText(v())
}

Exercise 3.4: req() to gate

Difficulty: Intermediate.

Show solution
ui <- fluidPage(textInput("name","Name:"), textOutput("o"))
server <- function(input, output) {
  output$o <- renderText({
    req(input$name)
    paste("Hello", input$name)
  })
}

Exercise 3.5: isolate

Difficulty: Advanced.

Show solution
ui <- fluidPage(numericInput("a","a:",1), actionButton("go","Go"), textOutput("o"))
server <- function(input, output) {
  output$o <- renderText({ input$go; isolate(input$a) })
}

Exercise 3.6: reactiveVal

Difficulty: Advanced.

Show solution
ui <- fluidPage(actionButton("go","+1"), textOutput("o"))
server <- function(input, output) {
  count <- reactiveVal(0)
  observeEvent(input$go, count(count() + 1))
  output$o <- renderText(count())
}

Section 4. Layout and dynamic UI (5 problems)

Exercise 4.1: tabsetPanel

Difficulty: Intermediate.

Show solution
ui <- fluidPage(tabsetPanel(tabPanel("A","panel A"), tabPanel("B","panel B")))

Exercise 4.2: navbarPage

Difficulty: Intermediate.

Show solution
ui <- navbarPage("App", tabPanel("One", "..."), tabPanel("Two", "..."))

Exercise 4.3: conditionalPanel

Difficulty: Advanced.

Show solution
ui <- fluidPage(checkboxInput("show", "show?"),
                conditionalPanel("input.show == true", "secret content"))

Exercise 4.4: insertUI / removeUI

Difficulty: Advanced.

Show solution
ui <- fluidPage(actionButton("add","Add"), tags$div(id = "host"))
server <- function(input, output) {
  observeEvent(input$add,
    insertUI("#host", "afterBegin", textInput(paste0("t", input$add), "text")))
}

Exercise 4.5: renderUI

Difficulty: Advanced.

Show solution
ui <- fluidPage(numericInput("n","n:",3), uiOutput("dyn"))
server <- function(input, output) {
  output$dyn <- renderUI({
    lapply(1:input$n, function(i) textInput(paste0("t",i), paste("Field",i)))
  })
}

Section 5. Modules and deployment (5 problems)

Exercise 5.1: Module UI

Difficulty: Advanced.

Show solution
counterUI <- function(id) {
  ns <- NS(id)
  tagList(actionButton(ns("go"), "+1"), textOutput(ns("o")))
}

Exercise 5.2: Module server

Difficulty: Advanced.

Show solution
counterServer <- function(id) moduleServer(id, function(input, output, session) {
  count <- reactiveVal(0)
  observeEvent(input$go, count(count()+1))
  output$o <- renderText(count())
})

Exercise 5.3: Wire module

Difficulty: Advanced.

Show solution
ui <- fluidPage(counterUI("c1"))
server <- function(input, output) counterServer("c1")

Exercise 5.4: rsconnect deployment basics

Difficulty: Advanced.

Show solution
# After setting account once:
# rsconnect::deployApp("path/to/app")

Exercise 5.5: Reactive value sharing across modules

Difficulty: Advanced.

Show solution
serverA <- function(id, shared) moduleServer(id, function(input, output, session) {
  observeEvent(input$go, shared(shared() + 1))
})

What to do next

  • R-Markdown-Exercises (coming), reproducible reporting.
  • Data-Visualization-Exercises (shipped), viz inside Shiny.