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
I'd really appreciate any advice, workarounds, or best practices! Thanks in advance!
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)
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)