Below is a step by step introduction to the bs4Dash structure. This is voluntarily very similar to shinydashboard, preventing users from having to learn another exotic framework.
This is the template to start with bs4Dash:
library(shiny) library(bs4Dash) shiny::shinyApp( ui = bs4DashPage( old_school = FALSE, sidebar_min = TRUE, sidebar_collapsed = FALSE, controlbar_collapsed = FALSE, controlbar_overlay = TRUE, title = "Basic Dashboard", navbar = bs4DashNavbar(), sidebar = bs4DashSidebar(), controlbar = bs4DashControlbar(), footer = bs4DashFooter(), body = bs4DashBody() ), server = function(input, output) {} )
The bs4DashPage()
takes optional argument such as old_school, which is FALSE by default. Whenever it is
TRUE, the page will have a fancy old design. The sidebar_collapsed argument enables to control how the bs4DashSidebar()
is displayed when the app starts. Similarly, controlbar_collapsed allow you to decide whether to display the bs4DashControlbar()
.
When sidebar_mini is TRUE, the sidebar icons are visible even when the sidebar is collapsed.
Finally, you can also give a title to the page.
Now, it is time to fill this template!
We will use the bs4DashSidebar()
function:
bs4DashSidebar( skin = "light", status = "primary", title = "bs4Dash", brandColor = "primary", url = "https://www.google.fr", src = "https://adminlte.io/themes/AdminLTE/dist/img/user2-160x160.jpg", elevation = 3, opacity = 0.8, bs4SidebarUserPanel( img = "https://image.flaticon.com/icons/svg/1149/1149168.svg", text = "Welcome Onboard!" ), bs4SidebarMenu( bs4SidebarHeader("Header 1"), bs4SidebarMenuItem( "Item 1", tabName = "item1", icon = "sliders" ), bs4SidebarMenuItem( "Item 2", tabName = "item2", icon = "id-card" ) ) )
A lot of options are available:
* two skins are available, namely "light" or "dark". I recommand using the "light" one.
* the title is only displayed when the sidebar is uncollapsed!
* the sidebar status determins which color bs4SidebarMenuItem()
have. There are 5 different colors:
"primary", "danger", "warning", "success", "info".
* brandColor: bakground color of the sidebar brand. I recommand using the same color as that chosen for status.
* src: sidebar brand image. SVGs, JPEG, PNG accepted.
I do not recommand to change the elevation nor opacity, altough possible.
We will use the bs4DashNavbar()
function:
bs4DashNavbar( skin = "light", status = "white", border = TRUE, sidebarIcon = "bars", controlbarIcon = "th", fixed = FALSE, leftUi = bs4DropdownMenu( show = TRUE, align = "left", status = "warning", menuIcon = "envelope-open", src = NULL ), rightUi = bs4DropdownMenu( show = FALSE, status = "danger", src = "https://www.google.fr", bs4DropdownMenuItem( message = "message 1", from = "Divad Nojnarg", src = "https://adminlte.io/themes/v3/dist/img/user3-128x128.jpg", time = "today", status = "danger", type = "message" ), bs4DropdownMenuItem( message = "message 2", from = "Nono Gueye", src = "https://adminlte.io/themes/v3/dist/img/user3-128x128.jpg", time = "yesterday", status = "success", type = "message" ) ) )
bs4DashNavbar()
allow you to change the bs4DashSidebar()
toggle icon, as well as that for the
bs4DashControlbar()
. 3 containers are available: leftUi to embed left UI elements, rightUI does the same thing on the right side. When putting a bs4DropdownMenu
in the leftUI slot, you better have to change the align argument
to "left", otherwise, the dropdown will open in the sidebar, which is not elegant. You can insert any content between the leftUI and rightUI slots. However, be careful not to overload the navbar.
This is not a mandatory element. We will use bs4DashControlbar()
:
bs4DashControlbar( skin = "light", title = "My right sidebar", sliderInput( inputId = "obs", label = "Number of observations:", min = 0, max = 1000, value = 500 ), column( width = 12, align = "center", radioButtons( inputId = "dist", label = "Distribution type:", c("Normal" = "norm", "Uniform" = "unif", "Log-normal" = "lnorm", "Exponential" = "exp") ) ) )
I also advise the user not to add to many elements inside the controlbar. The controlbar_overlay parameter in bs4DashPage
allows to push/cover the body content,
depending on its value.
We will use bs4DashFooter()
:
bs4DashFooter( copyrights = a( href = "https://twitter.com/divadnojnarg", target = "_blank", "@DivadNojnarg" ), right_text = "2018" )
Nothing special to add here!
This is the most important part since your dashboard content is displayed here:
bs4DashBody( bs4TabItems( bs4TabItem( tabName = "item1", fluidRow( lapply(1:3, FUN = function(i) { bs4Sortable( width = 4, p(class = "text-center", paste("Column", i)), lapply(1:2, FUN = function(j) { bs4Card( title = paste0("I am the ", j,"-th card of the ", i, "-th column"), width = 12, "Click on my header" ) }) ) }) ) ), bs4TabItem( tabName = "item2", bs4Card( title = "Card with messages", width = 9, userMessages( width = 12, status = "success", userMessage( author = "Alexander Pierce", date = "20 Jan 2:00 pm", src = "https://adminlte.io/themes/AdminLTE/dist/img/user1-128x128.jpg", side = NULL, "Is this template really for free? That's unbelievable!" ), userMessage( author = "Dana Pierce", date = "21 Jan 4:00 pm", src = "https://adminlte.io/themes/AdminLTE/dist/img/user5-128x128.jpg", side = "right", "Indeed, that's unbelievable!" ) ) ) ) ) )
The principle is pretty straightforward: all bs4DashBody()
elements must be embeded in a bs4TabItems()
list containing as may elements as the number of items. Each item is a bs4TabItem()
. Inportantly, the tabName argument must be provide and unique. Moreover, it must be identical to the
corresponding bs4SidebarMenuItem()
, so that the navigation between tabs work. This is exactly the same principle as for shinydashboard. Therefore, users should not be lost.
Below is the code for your first bs4Dash application:
Code
library(shiny) library(bs4Dash) shiny::shinyApp( ui = bs4DashPage( old_school = FALSE, sidebar_collapsed = TRUE, controlbar_collapsed = TRUE, title = "Basic Dashboard", navbar = bs4DashNavbar( skin = "light", status = "white", border = TRUE, sidebarIcon = "bars", controlbarIcon = "th", fixed = FALSE, leftUi = bs4DropdownMenu( show = TRUE, align = "left", status = "warning", menuIcon = "envelope-open", src = NULL ), rightUi = bs4DropdownMenu( show = FALSE, status = "danger", src = "https://www.google.fr", bs4DropdownMenuItem( message = "message 1", from = "Divad Nojnarg", src = "https://adminlte.io/themes/v3/dist/img/user3-128x128.jpg", time = "today", status = "danger", type = "message" ), bs4DropdownMenuItem( message = "message 2", from = "Nono Gueye", src = "https://adminlte.io/themes/v3/dist/img/user3-128x128.jpg", time = "yesterday", status = "success", type = "message" ) ) ), sidebar = bs4DashSidebar( skin = "light", status = "primary", title = "bs4Dash", brandColor = "primary", url = "https://www.google.fr", src = "https://adminlte.io/themes/AdminLTE/dist/img/user2-160x160.jpg", elevation = 3, opacity = 0.8, bs4SidebarUserPanel( img = "https://image.flaticon.com/icons/svg/1149/1149168.svg", text = "Welcome Onboard!" ), bs4SidebarMenu( bs4SidebarHeader("Header 1"), bs4SidebarMenuItem( "Item 1", tabName = "item1", icon = "sliders" ), bs4SidebarMenuItem( "Item 2", tabName = "item2", icon = "id-card" ) ) ), controlbar = bs4DashControlbar( skin = "light", title = "My right sidebar", sliderInput( inputId = "obs", label = "Number of observations:", min = 0, max = 1000, value = 500 ), column( width = 12, align = "center", radioButtons( inputId = "dist", label = "Distribution type:", c("Normal" = "norm", "Uniform" = "unif", "Log-normal" = "lnorm", "Exponential" = "exp") ) ) ), footer = bs4DashFooter( copyrights = a( href = "https://twitter.com/divadnojnarg", target = "_blank", "@DivadNojnarg" ), right_text = "2018" ), body = bs4DashBody( bs4TabItems( bs4TabItem( tabName = "item1", fluidRow( lapply(1:3, FUN = function(i) { bs4Sortable( width = 4, p(class = "text-center", paste("Column", i)), lapply(1:2, FUN = function(j) { bs4Card( title = paste0("I am the ", j,"-th card of the ", i, "-th column"), width = 12, "Click on my header" ) }) ) }) ) ), bs4TabItem( tabName = "item2", bs4Card( title = "Card with messages", width = 9, userMessages( width = 12, status = "success", userMessage( author = "Alexander Pierce", date = "20 Jan 2:00 pm", src = "https://adminlte.io/themes/AdminLTE/dist/img/user1-128x128.jpg", side = NULL, "Is this template really for free? That's unbelievable!" ), userMessage( author = "Dana Pierce", date = "21 Jan 4:00 pm", src = "https://adminlte.io/themes/AdminLTE/dist/img/user5-128x128.jpg", side = "right", "Indeed, that's unbelievable!" ) ) ) ) ) ) ), server = function(input, output) {} )
Advanced shiny user would probably design shiny modules to generate this page, which I really encourage. However, how to deal with modules is not the purpose of this article.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.