Open cpsievert opened 1 year ago
Does this refer to clicking on a sidebar icon taking you to a different page/tab of the app? Something like tabItem
in {shinydasboard}
or menuItem
in {bs4Dash}
? If so, yes please!
And having nav_menu()
like functionality where you can expand/collapse a list would be really nice to have.
This would be a really cool feature! Currently without possibility to create sidebar navigation it makes this framework a bit unusable especially for mid/larger side dashboard projects. Looking forward to see if you guys can implement it!
Just wanted to voice my support for this feature. I love what I see about bslib, but being able to create a "multipage sidebar dashboard" would make this even better :D
Something along the lines of this (using shinydashboard or bs4Dash):
library(shinydashboard)
ui <- dashboardPage(
dashboardHeader(title = "Basic dashboard"),
dashboardSidebar(
sidebarMenu(
menuItem("Dashboard", tabName = "dashboard", icon = icon("dashboard")),
menuItem("Widgets", tabName = "widgets", icon = icon("th"))
)
),
dashboardBody(
tabItems(
# First tab content
tabItem(tabName = "dashboard", h2("Dashboard")),
# Second tab content
tabItem(tabName = "widgets", h2("Widgets tab content"))
)
)
)
shinyApp(ui, function(input, output, session) {})
Is there anything that I could do to help this feature come alive?
being able to create a "multipage sidebar dashboard" would make this even better :D
You can make multi-page sidebar layouts. It's just that, currently, navigation must be in the header, not the sidebar (which is arguably better UX if you also want non-navigation controls in the sidebar)
Thanks for the comment. At the moment we use the left sidebar solely for navigation and want to use element-specific sidebars for control/filter etc.
If it helps, this is a quick hack that has the basic sidebar functionality (inspired by the shiny.tailwind
package, esp the twTabNav()
and twTabContent()
functions as well as the JS code).
It does not allow for submenus, but might be a good start if you want to go this way.
library(shiny)
library(bslib)
library(bsicons)
# Javascript to actually change the tabs =====
js <- '
function opentab(tabsetid, tabid) {
const tabs = document.querySelectorAll("." + tabsetid);
const contents = document.querySelectorAll("." + tabsetid + "-content");
// remove bsTab-active and bsTabContent-active classes and hide content
tabs.forEach(tab => {
tab.classList.remove("active");
// set active tab
if (tab.id == tabid) tab.classList.add("active");
});
contents.forEach(c => {
c.style.display = "none";
// show content tab
if (c.id == tabid + "-content") {
c.style.display = "block";
$(c).trigger("shown");
};
});
}'
# Helper functions to create the content and tab ====
nav_content <- function(..., ids = NULL, container_class = NULL,
content_class = NULL, tabsetid = "tabSet1") {
dots <- list(...)
if (is.null(ids)) ids <- paste0("bsTab-", seq_along(dots))
if (length(dots) != length(ids))
stop("ids has to have the same length as the provided tab navigation elements")
shiny::div(
class = container_class,
lapply(seq_along(dots), function(i) {
id <- dots[[i]]$attribs$id
if(is.null(id)) id <- ids[[i]]
idc <- strsplit(id, "-")[[1]]
if(idc[length(idc)] != "content") id <- paste0(id, "-content")
shiny::div(
class = paste(paste0(tabsetid, "-content"), content_class),
style = if(i == 1) "display: block;" else "display: none;",
id = id,
dots[[i]]
)
})
)
}
nav_tab <- function(..., ids = NULL, tabsetid = "tabSet1") {
dots <- list(...)
if (is.null(ids)) ids <- paste0("bsTab-", seq_along(dots))
if (length(dots) != length(ids))
stop("ids has to have the same length as the provided tab navigation elements")
shiny::div(
class = "row",
shiny::div(
class = "col-sm-12",
shiny::tags$ul(
style = "cursor: pointer;",
class = "nav nav-pills nav-stacked",
shiny::singleton(tags$script(shiny::HTML(js))),
lapply(seq_along(dots), function(i) {
id <- dots[[i]]$attribs$id
if(is.null(id)) id <- ids[[i]]
cl <- paste("nav-item", tabsetid, if (i == 1) "active")
tags$li(
class = cl, id = id,
onclick = sprintf("opentab('%s', '%s');", tabsetid, id),
tags$a(dots[[i]])
)
})
)
)
)
}
# Construct the UI =====
ui <- page_sidebar(
sidebar = sidebar(
nav_tab(
span(bs_icon("database"), span("Dashboard")),
span(bs_icon("bar-chart-fill"), span("Widgets"))
)
),
nav_content(
div(h1("Dashboard"), plotOutput("dashboard_plot")),
div(h1("Widgets"), plotOutput("widget_plot"))
)
)
# Construct the Server ====
server <- function(input, output, session) {
output$dashboard_plot <- renderPlot({
plot(1:100, cumsum(rnorm(100)), main = "Dashboard", type = "l")
})
output$widget_plot <- renderPlot({
boxplot(rnorm(100))
title("Widget")
})
}
shinyApp(ui, server)
Our company would also like to create dashboards with a sidebar naviagation (just like shinydashboards), but then with bs4 or higher. I read that you are planning to implement this in a new release. Is there a global timespan for the new release?
Here's a very nice example done in html
and js
, if you guys can package it as a function that would be best!
https://stackoverflow.com/a/76648897/22331901
From @WickM in #976:
I'd like to request the addition of a highly valuable feature: the ability to minify the sidebar, similar to the functionality showcased in the Bootstrap 5 documentation (getbootstrap.com/docs/5.0/examples/sidebars) and the bs4Dash package (rinterface.github.io/bs4Dash/reference/dashboardSidebar.html).
Will this support multiple levels of nesting?
Hi! Has anything changed since then?
Here's a very nice example done in
html
andjs
, if you guys can package it as a function that would be best! https://stackoverflow.com/a/76648897/22331901
I added a sidebar navigation with bslib alone to this post using navset_pill_list()
facing the issues that are mentioned here: https://github.com/rstudio/bslib/issues/980
The underlying component-level API could be something like:
And implementation wise could look quite similar to
navset_pill_list()
except useslayout_sidebar()
for the layout. We'd also have to face a tough decision on whether to supportnav_menu()
(i.e., dropdowns) in this context, or maybe introduce something more general, likenav_group()
, which would maybe avoid collapsing altogether)