Search code examples
rshinypickerinput

Highlighting a pickerInput using 'introjs' in R shiny


I would like to write an introduction tour using the function introjs for my R shiny app where one of the elements which gets highlighted is a pickerInput. But I am having troubles with the correct highlighting.

Here's an example:

library(shiny)
library(rintrojs)

ui <- fluidPage(
  introjsUI(),
  pickerInput(
    inputId = "color",
    label = "What is your favorite color?",
    choices = c("Red", "Green", "Blue")
  ),
  br(),
  actionButton(inputId = "tour", label = "Start Tour")
)

server <- function(input, output, session) {
  introjs(session)
  observeEvent(input$tour, {
    introjs(session, options = list(
      steps = list(
        list(element = "#color",
             intro = "Pick a color."),
        list(element = "#tour",
             intro = "This is a button.")
      )
    ))
  })
}

shinyApp(ui, server)

I would like to have the whole pickerInput highlighted (like it does when it highlights the button). But this is what happenes:

Something is wrong with the highlighting:

enter image description here

If I use the introBox instead of specifiying the elements of the tour within the introjs-call the problem is solved. But since I would like to implement multiple tours, the soluiton in this post suggests to not use the introBox.

Is there a way to highlight the pickerInput correctly?


Solution

  • You need to change the css selector you are highlighting. Use .dropdown instead of #color

    This

     list(element = "#color",
                 intro = "Pick a color."),
    

    should be changed to this:

            list(element = ".dropdown",
                 intro = "Pick a color."),
    

    Explanation: The html id that you defined as #color in the pickerInput() function isn't actually the html id for the dropdown menu, it's the html id for the option you selected from the dropdown menu. This is useful if you need to access that selection in the server, but to change the appearance of the dropdown menu (or target it with introjs), you have to use the css selector for #color's parent container which is .dropdown.

    This is the dropdown menu class not the id for that specific dropdown menu, so if you have multiple dropdown menus they may all get selected. If that's a problem you could work around it by targeting that menu's html id instead or wrapping that dropdown menu in a div and then target that div.

    Edit: If you have multiple dropdown menus

    Use the web developer tools to find their html ids and then target them individually. If you want memorable names you'll probably need to wrap them in tags$div() like this tags$div(id="memorable-name",pickerInput(...) ), but then you'll probably also need to adjust the css for #memorable-name to get the div to be the same size as the child dropdown menu.

    Here's an example of just using the html ids found using the developer tools for two dropdown menus

    library(shiny)
    library(rintrojs)
    
    ui <- fluidPage(
      introjsUI(),
      pickerInput(
        inputId = "color",
        label = "What is your favorite color?",
        choices = c("Red", "Green", "Blue")
      ),
      br(),
      pickerInput(
        inputId = "fruit",
        label = "What is your favorite fruit?",
        choices = c("Apples", "Oranges", "Bananas")
      ),
      br(),
      actionButton(inputId = "tour", label = "Start Tour")
    )
    
    server <- function(input, output, session) {
      introjs(session)
      observeEvent(input$tour, {
        introjs(session, options = list(
          steps = list(
            list(element = "div.form-group:nth-child(1) > div:nth-child(2)",
                 intro = "Pick a color."),
            list(element = "div.form-group:nth-child(3) > div:nth-child(2)",
                 intro = "Pick a fruit."),
            list(element = "#tour",
                 intro = "This is a button.")
            
            
          )
        ))
      })
    }
    
    shinyApp(ui, server)