rshinybslib

Why does the conditionalPanel fail to work when using a bslib bootswatch theme version 5?


I am trying to create a simple application where the sidebar will change depending on which tabsetPanel the user is currently selecting. It works with R Shiny natively but when I try and style it with bslib, it starts breaking. I suspect it is a result of some Javascript or NS conflicts.

Additionally, it only breaks when I use versions 4 or 5 of Bootswatch themes. I have provided a minimal example below.

Why does the conditionalPanel with textInput id = "textInput2" not show up? If you change the version of bootswatch back to version 3, it works.

library(shiny)
library(bslib)

options(shiny.port = 8080)

# UI/Server for Module_1
module_1_ui <- function(id) {
  ns <- NS(id)
  tabPanel("Main", fluid = TRUE,
      sidebarLayout(
        sidebarPanel(
          textInput(ns('textInput'), 'Enter text')
        ),
        mainPanel(
          uiOutput(ns('textOutput'))
        )
      )
  )
  
}

module_1_server <- function(id, session) {
  moduleServer(id, function(input, output, session) {
    ns <- session$ns

    output$textOutput <- renderUI({
      req(input$textInput)
      HTML(paste0('You entered: ', input$textInput))
    })
    
  })

}
# UI/Server for Module_2
module_2_ui <- function(id) {
  ns <- NS(id)

  tabPanel("Side", fluid = TRUE,
      sidebarLayout(
        sidebarPanel(
          HTML("This always shows!"),
          br(),
          conditionalPanel(
            condition =  sprintf("input['%s'] == 'Test2'", ns("side_tabsets")),
            textInput(ns('textInput2'), 'Enter text')
          )
        ),
        mainPanel(
          uiOutput(ns('sideOutput'))
        )
      )
  )
}

module_2_server <- function(id, session) {

  moduleServer(id, function(input, output, session) {
    ns <- session$ns

    output$sideOutput <- renderUI({
      tabsetPanel(
        id = ns("side_tabsets"),
        tabPanel(title = "Test1", br(), actionButton(ns("button1"), "Button 1")),
        tabPanel(title = "Test2", br(), actionButton(ns("button2"), "Button 2"))
      )
    })
  })
}

# Overall UI
ui <- fluidPage(
  theme = bs_theme(bootswatch = "cosmo", version = 5),
  navbarPage(title = "",
    module_1_ui("main"),
    module_2_ui("side")
  )
)

# Overall Server
server <- function(input, output, session) {
  module_1_server("main", session)
  module_2_server("side", session)
}



shinyApp(ui = ui, server = server)

Here is my sessionInfo:

> sessionInfo()
R version 4.3.3 (2024-02-29)
Platform: x86_64-apple-darwin20 (64-bit)
Running under: macOS Sonoma 14.3.1

Matrix products: default
BLAS:   /Library/Frameworks/R.framework/Versions/4.3-x86_64/Resources/lib/libRblas.0.dylib 
LAPACK: /Library/Frameworks/R.framework/Versions/4.3-x86_64/Resources/lib/libRlapack.dylib;  LAPACK version 3.11.0

locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8

time zone: America/Los_Angeles
tzcode source: internal

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
[1] bslib_0.8.0   shiny_1.8.1.1

loaded via a namespace (and not attached):
 [1] digest_0.6.36     later_1.3.2       R6_2.5.1          httpuv_1.6.15    
 [5] fastmap_1.2.0     magrittr_2.0.3    cachem_1.1.0      htmltools_0.5.8.1
 [9] lifecycle_1.0.4   promises_1.3.0    cli_3.6.3         xtable_1.8-4     
[13] sass_0.4.9        jquerylib_0.1.4   compiler_4.3.3    tools_4.3.3      
[17] mime_0.12         Rcpp_1.0.13       jsonlite_1.8.8    rlang_1.1.4     

I have tried redownloading shiny and bslib to see if it was a problem with the package installation.


Solution

  • bslib has its own page_* functions for generating page layouts which should be used in favor of shiny's *Page functions. Replace fluidPage() and navbarPage() with page_fluid() and page_navbar() and it will work.

    enter image description here

    library(shiny)
    library(bslib)
    
    options(shiny.port = 8080)
    
    # UI/Server for Module_1
    module_1_ui <- function(id) {
      ns <- NS(id)
      tabPanel("Main", fluid = TRUE,
               sidebarLayout(
                 sidebarPanel(
                   textInput(ns('textInput'), 'Enter text')
                 ),
                 mainPanel(
                   uiOutput(ns('textOutput'))
                 )
               )
      )
      
    }
    
    module_1_server <- function(id, session) {
      moduleServer(id, function(input, output, session) {
        ns <- session$ns
        
        output$textOutput <- renderUI({
          req(input$textInput)
          HTML(paste0('You entered: ', input$textInput))
        })
        
      })
      
    }
    # UI/Server for Module_2
    module_2_ui <- function(id) {
      ns <- NS(id)
      
      tabPanel("Side", fluid = TRUE,
               sidebarLayout(
                 sidebarPanel(
                   HTML("This always shows!"),
                   br(),
                   conditionalPanel(
                     condition =  sprintf("input['%s'] == 'Test2'", ns("side_tabsets")),
                     textInput(ns('textInput2'), 'Enter text')
                   )
                 ),
                 mainPanel(
                   uiOutput(ns('sideOutput'))
                 )
               )
      )
    }
    
    module_2_server <- function(id, session) {
      
      moduleServer(id, function(input, output, session) {
        ns <- session$ns
        
        output$sideOutput <- renderUI({
          tabsetPanel(
            id = ns("side_tabsets"),
            tabPanel(title = "Test1", br(), actionButton(ns("button1"), "Button 1")),
            tabPanel(title = "Test2", br(), actionButton(ns("button2"), "Button 2"))
          )
        })
      })
    }
    
    # Overall UI
    ui <- page_fluid(
      theme = bs_theme(bootswatch = "cosmo", version = 5),
      page_navbar(title = "",
                  module_1_ui("main"),
                  module_2_ui("side")
      )
    )
    
    # Overall Server
    server <- function(input, output, session) {
      module_1_server("main", session)
      module_2_server("side", session)
    }
    
    
    shinyApp(ui = ui, server = server)