You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用bslib Bootswatch 5主题时Shiny的conditionalPanel失效原因

问题描述

开发R Shiny应用时,期望侧边栏内容能随tabsetPanel的选中项切换。该功能在原生Shiny中正常,但使用bslib的Bootswatch 4/5主题时异常:带有textInput(id='textInput2')的conditionalPanel无法显示,切换回Bootswatch 3则恢复正常。推测是JavaScript或命名空间冲突导致,已尝试重新安装shiny和bslib,问题未解决。

最小复现代码

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)

Session信息

> 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     

解决方案

问题根源

Bootstrap 4及以上版本中,Shiny的tabsetPanel组件逻辑发生变化:input$<tabset_id>返回的不再是tab的标题文本,而是tab的value属性值。若未显式指定value,Shiny会自动生成随机ID而非使用标题,导致原conditionalPanel中的条件判断(匹配标题"Test2")无法触发。

修复步骤

给tabsetPanel内的每个tabPanel显式添加value参数,确保参数值与conditionalPanel的判断值一致。

修改后的完整代码

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"),
        # 显式指定value参数,与条件判断值一致
        tabPanel(title = "Test1", value = "Test1", br(), actionButton(ns("button1"), "Button 1")),
        tabPanel(title = "Test2", value = "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)

验证说明

修改后切换到"Side"标签页下的"Test2"子tab时,侧边栏的textInput2会正常显示,Bootswatch 5主题下功能恢复正常。


内容的提问来源于stack exchange,提问作者Hpatel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 09:35:01