rshinytabs

Show tabPanels as conditionalPanel inside tabsetPanel


I have checked SO for similar posts and have not found this same or similar issue anywhere. My apologies if I missed something, however, I do believe this question has not been asked before.

What I would like to do is to show parts of my UI depending on user input / application output. A minimal working example of my situation is attached here:

ui <- fluidPage(
  sidebarLayout(
    sidebarPanel = sidebarPanel(
      checkboxInput("checkboxInput1Id", "Check to show first tab"),
      conditionalPanel(
        "input.checkboxInput1Id == true",
        checkboxInput("checkboxInput2Id", "Check to show second set of tabs")
      )
    ),
    
    mainPanel = mainPanel(
      conditionalPanel(
        "input.checkboxInput1Id == true", 
        tabsetPanel(
          tabPanel("Tab 1", plotOutput("plot1")),
          conditionalPanel(
            "input.checkboxInput2Id == true",
            tabsetPanel(
              tabPanel("Tab 2.1", plotOutput("plot2.1")),
              tabPanel("Tab 2.2", plotOutput("plot2.2")),
              tabPanel("Tab 2.3", plotOutput("plot2.3"))
            )
          )
        ))
    )
  )
  
)

server <- function(input, output, session) {
  x <- iris$Sepal.Length
  y <- iris$Sepal.Width
  z <- iris$Petal.Length
  
  output$plot1 <- renderPlot(hist(islands))
  output$plot2.1 <- renderPlot(plot(x ~ y))
  output$plot2.2 <- renderPlot(plot(x ~ z))
  output$plot2.3 <- renderPlot(plot(y ~ z))
}

runApp(shinyApp(ui=ui, server=server))

As one can see from the layout of my UI's mainPanel, I want the inner conditionalPanel to be part of the tabsetPanel which includes the first conditionalPanel. In other words:

  1. On app startup: only show sidebarPanel
  2. On selection of checkboxInput1Id: show checkboxInput2Id and show conditionalPanel #1
  3. On selection of checkboxInput2Id: show conditionalPanel #2 such that the three tabPanels contained appear next to Tab 1.

The problem I face is that this does not seem possible (or I am using the API incorrectly). The second set of tabs appears underneath my first tab and I cannot make it appear alongside the first tab. Any advice on how to fix this? Here is a screenshot of the app's look and an indication of where I want the tabs to appear:

enter image description here

Edit: referring to Ismirsehregal's answer, I am now finding it hard to hide a tab when working from a modularized context. My code is such as this:

ui <- function(id) {
  ns <- NS(id)

  sidebarLayout(
    sidebarPanel = sidebarPanel(...),

    mainPanel = mainPanel(
      conditionalPanel(
        style = "display: none;",
        condition = "input.someCondition == true",
        tabsetPanel(
          id = ns("foobar"),
          tabPanelFromModule(ns("moduleName")) # ns("moduleName") is the resulting tabPanel's value,
          someMoreTabPanels
        )
      )
    )
  )
}

server <- function(id) {
  moduleServer(id, function(input, output, session) {
    observe({
      hideTab(inputId=ns("foobar"), target=ns("moduleName"))
    }) %>% bindEvent(input$someInput)
  }
}

This should hide the tabPanel, but does not do so. I have checked the HTML code of my UI object and it looks like I am referring correctly to the tabsetPanel as well as the tabPanel held within.


Solution

  • In this case I'd suggest using showTab and hideTab instead of conditionalPanel.

    Please note: the tabsetPanel needs an id for this to work:

    
    library(shiny)
    
    ui <- fluidPage(
      sidebarLayout(
        sidebarPanel = sidebarPanel(
          checkboxInput("checkboxInput1Id", "Check to show first tab"),
          conditionalPanel(style = "display: none;",
            "input.checkboxInput1Id == true",
            checkboxInput("checkboxInput2Id", "Check to show second set of tabs")
          )
        ),
        
        mainPanel = mainPanel(
          conditionalPanel(style = "display: none;",
            "input.checkboxInput1Id == true", 
            tabsetPanel(id = "tabs",
              tabPanel("Tab 1", plotOutput("plot1")),
              tabPanel("Tab 2.1", plotOutput("plot2.1")),
              tabPanel("Tab 2.2", plotOutput("plot2.2")),
              tabPanel("Tab 2.3", plotOutput("plot2.3"))
            ))
        )
      )
      
    )
    
    server <- function(input, output, session) {
      x <- iris$Sepal.Length
      y <- iris$Sepal.Width
      z <- iris$Petal.Length
      
      output$plot1 <- renderPlot(hist(islands))
      output$plot2.1 <- renderPlot(plot(x ~ y))
      output$plot2.2 <- renderPlot(plot(x ~ z))
      output$plot2.3 <- renderPlot(plot(y ~ z))
      
      observeEvent(input$checkboxInput2Id, {
        if(isTRUE(input$checkboxInput2Id)){
          # showTab(inputId = "tabs", target = "Tab 2.1")
          lapply(list("Tab 2.1", "Tab 2.2", "Tab 2.3"), showTab, inputId = "tabs")
        } else {
          # hideTab(inputId = "tabs", target = "Tab 2.1")
          lapply(list("Tab 2.1", "Tab 2.2", "Tab 2.3"), hideTab, inputId = "tabs")
        }
      })
    }
    
    runApp(shinyApp(ui=ui, server=server))
    

    Furthermore, I applied this fix to avoid the flashing of the conditionalPanel on app start.

    Also related:

    https://mastering-shiny.org/action-dynamic.html