Search code examples
rshinylapplytabpanel

R Shiny dynamic multilevel/nested tabPanel with renderUI


I want to create a tabsetPanel within an other tabsetPanel. The number of tabs of the second tabsetPanel should depend on a selectizeInput in the first-level tabs.

This minimal example seems to be almost ok. However, when selecting the second level tabs in the input box the created tabs immediately disappears.

The challenge is how to get the output of selectizeInput in the lapply function.

    library(shiny)

    ui <- fluidPage(mainPanel(
      selectizeInput(
        inputId  = "letters",
        label    = "Select letters for level 1 tabs",
        choices  = LETTERS,
        selected = c('A', 'B', 'C'),
        multiple = TRUE
      ),

      uiOutput('mytabs')

    ))


server <- function(input, output) {

  output$mytabs <- renderUI({

    level1Tabs <- lapply(1:length(input$letters),
                         function(i) {
                           tabPanel(input$letters[i],
                                    test2 <- renderUI({
                                      selectizeInput(
                                        inputId  = 'numbers',
                                        label    = 'Select numbers for level 2 tabs',
                                        choices  =  1:10,
                                        multiple = TRUE
                                      )
                                    }),


                                    do.call(tabsetPanel,
                                            lapply(1:length(input$numbers), function(j) {
                                              tabPanel(input$numbers[j],
                                                       h5('test'))

                                            })))


                         })

    do.call(tabsetPanel, level1Tabs)

  })

}

# Run the application
shinyApp(ui = ui, server = server)

Solution

  • The answers is quite simple: just put the innerlevel tabsetPanel wihtin renderUI

    renderUI({
      do.call(tabsetPanel,
              lapply(1:length(input$numbers), function(j) {
                tabPanel(input$numbers[j],
                         h5('test'))
    
              }))
    })
    

    This will prevent updating/refresing the selectizeInput (numbers)