Navigating a web app without pointing and clicking is common in many popular websites. For example, GitHub has a number of hotkeys, all of which can be viewed by pressing ?.

The same functionality can be used in shiny apps with keys. In this vignette, we’ll go over a small example that demonstrates how you can use keys to navigate a shiny app with tabs. First we start by loading the required packages:

Next, we define the UI part of our app:

ui <- fluidPage(
  useKeys(),
  keysInput("keys", c("1", "2", "3")),
  tabsetPanel(
    id = "tabs",
    tabPanel("Tab 1", "We're on tab 1"),
    tabPanel("Tab 2", "We're on tab 2"),
    tabPanel("Tab 3", "We're on tab 3")
  )
)

This interface has 3 components:

  1. Javascript dependencies
  2. A keys input with some defined hotkeys
  3. A tabsetPanel

It’s important to note that the tabsetPanel has an ID assigned to it. An ID must be assigned to a tabsetPanel in order to observe which tab is active from the server, ?tabsetPanel will give some additional detail on this.

The last step is to write the server logic:

server <- function(input, output, session) {
  observeEvent(input$keys, {
    switch (input$keys,
      "1" = updateTabsetPanel(session, "tabs", "Tab 1"),
      "2" = updateTabsetPanel(session, "tabs", "Tab 2"),
      "3" = updateTabsetPanel(session, "tabs", "Tab 3")
    )
  })
}

With this, we can observe which hotkeys the user presses and then update which tab is active. We could even bypass the switch call by providing a value to each tabPanel that corresponds with the hotkeys:

tabPanel("Tab 1", "We're on tab 1", value = "1")
tabPanel("Tab 2", "We're on tab 2", value = "2")
tabPanel("Tab 3", "We're on tab 3", value = "3")

The server would then be simplified to:

observeEvent(input$keys, {
  updateTabsetPanel(session, "tabs", input$keys)
})

This is pretty much all you need to start using keys for conditional logic in your app. If you’re looking for more advanced logic, you can be creative with functions like addKeys, removeKeys, and recordKeys.

Finally, below is the full scripts for both apps demonstrated above:

# without tab values assigned
library(keys)
library(shiny)

ui <- fluidPage(
  useKeys(),
  keysInput("keys", c("1", "2", "3")),
  tabsetPanel(
    id = "tabs",
    tabPanel("Tab 1", "We're on tab 1"),
    tabPanel("Tab 2", "We're on tab 2"),
    tabPanel("Tab 3", "We're on tab 3")
  )
)

server <- function(input, output, session) {
  observeEvent(input$keys, {
    switch (input$keys,
      "1" = updateTabsetPanel(session, "tabs", "Tab 1"),
      "2" = updateTabsetPanel(session, "tabs", "Tab 2"),
      "3" = updateTabsetPanel(session, "tabs", "Tab 3")
    )
  })
}

shinyApp(ui, server)

# with tab values assigned
library(keys)
library(shiny)

ui <- fluidPage(
  useKeys(),
  keysInput("keys", c("1", "2", "3")),
  tabsetPanel(
    id = "tabs",
    tabPanel("Tab 1", "We're on tab 1", value = "1"),
    tabPanel("Tab 2", "We're on tab 2", value = "2"),
    tabPanel("Tab 3", "We're on tab 3", value = "3")
  )
)

server <- function(input, output, session) {
  observeEvent(input$keys, {
    updateTabsetPanel(session, "tabs", input$keys)
  })
}

shinyApp(ui, server)