rshinybslib

How to link navset_pill_list -> nav_panel() with UI elements and adjust layout width in bslib?


I'm currently exploring the bslib package and have two related questions regarding navigation behavior and layout design in Shiny apps.

1) Navigation Behavior

In the shinydashboard package, I could use the tabName argument in a menuItem() to declaratively link it to a tabItem() without any server-side logic. Is there a similar approach in bslib?

Currently, I’m using the value argument in bslib::nav_panel() and handling the logic manually via server code like this:

output$main_content <- shiny::renderUI({
  if (input$sidebar_tabs == "my_tab") {
    # return corresponding UI
  }
})

Is there a built-in way in bslib to do this more declaratively, without server-side renderUI()?

2) Layout Design

  1. As shown in the screenshot, the bslib::navset_pill_list() component appears narrower than other sidebar elements like card() or value_box(). How can I make it match the width of the other sidebar items?
  2. Also, I noticed that shiny::radioButtons() don't use the full width of their container card(). Is there a way to make them expand horizontally?

I'd really appreciate any advice, workarounds, or best practices! Thanks in advance!

enter image description here

This is my working example code:

utils::globalVariables(c("name_input"))

ui <- bslib::page_sidebar(
  theme = bslib::bs_theme(version = 5, bootswatch = "minty"),
  
  sidebar = bslib::sidebar(
    bslib::card(
      title = "User Info",
      shiny::textInput("name_input", "User ID"),
      shiny::actionButton("submit_btn", "Load User")
    ),
    
    bslib::value_box(
      title = "Status",
      value = shiny::textOutput("patient_status"),
      showcase = shiny::icon("user")
    ),
    
    bslib::navset_pill_list(
      id = "sidebar_tabs",
      bslib::nav_panel(title = "Survey", value = "survey"),
      bslib::nav_panel(title = "Data Input", value = "data_input"),
      bslib::nav_panel(title = "Metrics", value = "metrics"),
      bslib::nav_panel(title = "Notes", value = "notes"),
      bslib::nav_spacer()
    )
  ),
  
  shiny::uiOutput("main_content")
)

server <- function(input, output, session) {
  shiny::observeEvent(input$submit_btn, {
    shiny::showModal(shiny::modalDialog(
      title = "User Loaded",
      paste("User data has been loaded."),
      easyClose = TRUE
    ))
  })
  
  output$patient_status <- shiny::renderText({
    if (input$submit_btn == 0 || input$name_input == "") {
      "No user loaded"
    } else {
      input$name_input
    }
  })
  
  output$main_content <- shiny::renderUI({
    if (input$sidebar_tabs == "survey") {
      bslib::card(
        title = "Survey Questions",
        bslib::navset_tab(
          id = "question_tabs",
          
          bslib::nav_panel("Question A",
                           shiny::radioButtons("question1", 
                                               "In the last four weeks, how often did you feel that you had too many responsibilities to handle at once?", 
                                               choices = c(
                                                 "Almost all of the time, I felt overwhelmed by my tasks and responsibilities.",
                                                 "Most of the time, I found it hard to manage everything I had to do.",
                                                 "Sometimes I struggled, but it was manageable.",
                                                 "Rarely did I feel overwhelmed by responsibilities.",
                                                 "I never felt like I had too much to handle."
                                               )
                           )
          ),
          
          bslib::nav_panel("Question B",
                           shiny::radioButtons("question2", 
                                               "How confident are you in your ability to adapt to unexpected changes in your daily routine?", 
                                               choices = c(
                                                 "Extremely confident – I can quickly adjust and find new solutions.",
                                                 "Very confident – I usually handle changes well.",
                                                 "Somewhat confident – I manage, but it takes time.",
                                                 "Not very confident – I find changes quite difficult to manage.",
                                                 "Not confident at all – I struggle significantly with unexpected changes."
                                               )
                           )
          ),
          
          bslib::nav_panel("Question C",
                           shiny::radioButtons("question3", 
                                               "Please indicate how much you agree with the following statement: 'I feel supported by the people around me.'", 
                                               choices = c(
                                                 "Strongly agree – I have a strong support network and feel encouraged.",
                                                 "Agree – I feel mostly supported by friends, family, or colleagues.",
                                                 "Neutral – I sometimes feel supported, sometimes not.",
                                                 "Disagree – I often feel alone in facing challenges.",
                                                 "Strongly disagree – I do not feel supported at all."
                                               )
                           )
          )
        )
      )
    } else if (input$sidebar_tabs == "data_input") {
      bslib::card(
        title = "Data Input",
        shiny::textInput("input_1", "Input Field 1:"),
        shiny::textInput("input_2", "Input Field 2:"),
        shiny::textInput("input_3", "Input Field 3:"),
        shiny::textInput("input_4", "Input Field 4:"),
        shiny::textInput("input_5", "Input Field 5:"),
        shiny::textInput("input_6", "Input Field 6:")
      )
    }
  })
}

shiny::shinyApp(ui, server)

  })
}

shiny::shinyApp(ui, server)

Solution

  • For 2.1 you could use widths = c(11,1), and the other two were provided by @smartse namely, conditionalPanel() and width="100%" . Try this

    utils::globalVariables(c("name_input"))
    library(DT)
    library(shiny)
    library(bslib)
    
    survey_ui <- tagList(
      bslib::card(
        title = "Survey Questions",
        bslib::navset_tab(
          id = "question_tabs",
          
          bslib::nav_panel("Question A",
                           shiny::radioButtons("question1", 
                                               "In the last four weeks, how often did you feel that you had too many responsibilities to handle at once?", 
                                               choices = c(
                                                 "Almost all of the time, I felt overwhelmed by my tasks and responsibilities.",
                                                 "Most of the time, I found it hard to manage everything I had to do.",
                                                 "Sometimes I struggled, but it was manageable.",
                                                 "Rarely did I feel overwhelmed by responsibilities.",
                                                 "I never felt like I had too much to handle."
                                               ), width = "100%"
                           )
          ),
          
          bslib::nav_panel("Question B",
                           shiny::radioButtons("question2", 
                                               "How confident are you in your ability to adapt to unexpected changes in your daily routine?", 
                                               choices = c(
                                                 "Extremely confident – I can quickly adjust and find new solutions.",
                                                 "Very confident – I usually handle changes well.",
                                                 "Somewhat confident – I manage, but it takes time.",
                                                 "Not very confident – I find changes quite difficult to manage.",
                                                 "Not confident at all – I struggle significantly with unexpected changes."
                                               ), width = "100%"
                           )
          ),
          
          bslib::nav_panel("Question C",
                           shiny::radioButtons("question3", 
                                               "Please indicate how much you agree with the following statement: 'I feel supported by the people around me.'", 
                                               choices = c(
                                                 "Strongly agree – I have a strong support network and feel encouraged.",
                                                 "Agree – I feel mostly supported by friends, family, or colleagues.",
                                                 "Neutral – I sometimes feel supported, sometimes not.",
                                                 "Disagree – I often feel alone in facing challenges.",
                                                 "Strongly disagree – I do not feel supported at all."
                                               ), width = "100%"
                           )
          )
        )
      )
    )
    
    ui <- bslib::page_sidebar(
      theme = bslib::bs_theme(version = 5, bootswatch = "minty"),
    
      sidebar = bslib::sidebar(
        bslib::card(
          title = "User Info",
          shiny::textInput("name_input", "User ID"),
          shiny::actionButton("submit_btn", "Load User")
        ),
        
        bslib::value_box(
          title = "Status",
          value = shiny::textOutput("patient_status"),
          showcase = shiny::icon("user")
        ),
        
        bslib::navset_pill_list(
          id = "sidebar_tabs", widths = c(11,1),
          bslib::nav_panel(title = "Survey", value = "survey"),
          bslib::nav_panel(title = "Data Input", value = "data_input"),
          bslib::nav_panel(title = "Metrics", value = "metrics"),
          bslib::nav_panel(title = "Notes", value = "notes"),
          bslib::nav_spacer()
        )
      ), ### end of sidebar
      
      conditionalPanel( "input.sidebar_tabs == 'survey'",
                        survey_ui
      ),
      conditionalPanel( "input.sidebar_tabs == 'data_input'",
                        DTOutput("mt")
      ),
      conditionalPanel( "input.sidebar_tabs == 'metrics'",
                        plotOutput("p")
      ),
      conditionalPanel( "input.sidebar_tabs == 'notes'",
                        textOutput("txt") 
      )
        
    
    )
    
    server <- function(input, output, session) {
      output$mt <- renderDT(mtcars)
      output$p <- renderPlot(plot(cars))
      output$txt <- renderText(print("Hello"))
    }
    
    shiny::shinyApp(ui, server)