How to create a Shiny Dashboard
Center for Evaluation and Development (C4ED)
2024
Shinydashboard, is a specialised package for creating dashboards.shinyApp() is also needed to integrate the UI and server togetherShinydashboard distinguishes itself through its unique UI setup, offering a structured, customizable environment for data presentation and interaction.
dashboardPage() and not fluidPage()ui,dashboardHeader, dashboardSidebar, and dashboardBody functions.three main components as:
dashboardPage function then integrates these elements within the UI.
dashboardHeaderdashboardHeader, is a visual element in shinydashboard’s layout.
skin = "green" in side the dashboardPage(), i.e., dashboardPage(skin = "green", header, sidebar, body)dashboardHeader: The titleWidth argument in dashboardHeader allows customization of the title section’s width.
dashboardHeader(disable = TRUE).
sidebarMenu()The sidebar usually contains a sidebarMenu(), which needs a unique ID and a list of menu items.
Each menuItem() consists of the title, a tabName that will be used to refer to the tab later, and an icon. There are a list of the available free icons at fontawesome.
Each menuItem can correspond to different content displayed in the main body of the dashboard.
Its width can also be adjusted to be in line with the header width.
We can also disable the sidebarMenu if it’s unwanted, by setting specifying: dashboardSidebar(disable = TRUE)
Function: sidebarMenu() within dashboardSidebar() organizes your navigation tabs.
Navigation Tabs: Use menuItem() within sidebarMenu() to create tabs similar to tabPanel in Shiny.
Content Linking: Each menuItem() in sidebarMenu() corresponds to a tabItem() in the body.
tabName attributes match for proper content display.Icons: Use icon() within menuItem() for visual representation.
Badges: Add badgeLabel and badgeColor to highlight or categorize menu items.
External Links: Include href in menuItem() for external URLs.
Control tab opening behaviour with the newtab argument.
sidebar <- dashboardSidebar(width = 300,
sidebarMenu(
menuItem("Main Dashboard", tabName = "dashboard", icon = icon("dashboard")),
menuItem("Widgets", tabName = "widgets", icon = icon("th"),
badgeLabel = "Newly added", badgeColor = "green"),
menuItem("Charts", tabName = "charts", icon = icon("chart")),
menuItem("Tables", tabName = "tables", icon = icon("table")),
menuItem("my website Link", href = "https://yebelay.rbind.io",
icon = icon("external-link"))) ) 
sliderInput and textInput in the sidebar for user interaction.sidebarSearchForm() with textId and buttonId.
input$searchText and input$searchButton.sidebar <- dashboardSidebar(width = 300, sidebarMenu(
menuItem("Main Dashboard", tabName = "dashboard", icon = icon("dashboard")),
menuItem("Widgets", tabName = "widgets", icon = icon("th"),
badgeLabel = "Newly added", badgeColor = "green"),
menuItem("Charts", tabName = "charts", icon = icon("chart")),
menuItem("Tables", tabName = "tables",icon = icon("table")),
sliderInput("slider", "Slider", min = 1, max = 100, value = 50),
checkboxInput("checkbox", "Checkbox", value = TRUE),
radioButtons("radio", "Radio Buttons",
choices = c("Option 1", "Option 2", "Option 3")),
sidebarSearchForm(textId = "search", buttonId = "searchButton",
label = "Search..."))) dashboardBody()The main part of the app goes inside dashboardBody().
It’s the area to displays outputs and accommodate user inputs.
The tabName has to match the name you used in the sidebar menuItem(), so that tab shows when the user clicks on the corresponding menu item.
tabName.Most shinydashboard apps organise the parts inside boxes.
tabItem(tabName = "dashboard",
box(title = "Personal Info", collapsible = TRUE,
textInput("given", "Given Name"),
textInput("surname", "Surname"),
selectInput("pet", "What is your favourite pet?",
c("cats", "dogs", "ferrets"))),
box(title = "Biography", solidHeader = TRUE,
textAreaInput("bio", NULL, height = "100px",
placeholder = "brief bio")))You can use an infoBox() or a valueBox() to highlight a small amount of information.
The default background is aqua, but the basic template changes this to the skin colour.
However, you can customise this by setting the color argument.
Shinydashboard uses a grid system that is 12 units across. The default width of boxes is 6, and info and value boxes are 4.
Create a box with multiple tabs using tabBox(), which contains tabPanel().
tabItem(tabName = "dashboard",
tabBox(title = "Test Yourself 1",
tabPanel("Question", "What function creates tabBox contents?"),
tabPanel("Answer", "tabPanel()") ),
tabBox(title = "Test Yourself 2",
side = "right", selected = "Question",
tabPanel("Answer", "selected"),
tabPanel("Question", "What attribute changes the default tab?")) )fluidRow().tabItem(tabName = "dashboard",
fluidRow(box("A", title = "2x100", width = 2, height = 100),
box("B", title = "1x100", width = 1, height = 100),
box("C", title = "2x200", width = 2, height = 200),
box("D", title = "3x300", width = 3, height = 300),
box("E", title = "4x100", width = 4, height = 100),
box("F", title = "5x100", width = 5, height = 100),
box("G", title = "7x100", width = 7, height = 100)))column() with a specific width.width to, an element inside with a width of 6 will be half the column width.tabItem(tabName = "dashboard",
column(width = 6,
box("A", title = "12x100", width = 12, height = 100),
box("B", title = "6x100", width = 6, height = 100),
box("C", title = "6x200", width = 6, height = 200)),
column(width = 4,
box("D", title = "12x300", width = 12, height = 300),
box("E", title = "12x100", width = 12, height = 100)),
column(width = 2,
box("F", title = "12x100", width = 12, height = 100),
box("G", title = "12x100", width = 12, height = 100)))box(). These containers can hold various UI components.fluidRow() for a structured layout.title argument for descriptive headings.status argument (e.g., “primary” for blue, “warning” for yellow).solidHeader = TRUE for a more prominent header.collapsible = TRUE, allowing users to collapse or expand the box content.background argument for a unique look.# Sample dashboardBody with various box customisations
body = dashboardBody(fluidRow(
box(title = "Box 1", status = "primary", "Content", solidHeader = TRUE),
box(title = "Box 2", plotOutput("plot1", height = 250), solidHeader = TRUE),
box(title = "Box 3", status = "warning", "Content", solidHeader = TRUE,
collapsible = TRUE),
box(title = "Box 4", background = "black", "Content"))) infoBox is a UI component in shinydashboard designed to display key metrics, such as numerical or textual values, along with icons for visual emphasis.
It’s effective for showcasing statistics like user count, sales figures, or progress metrics.
Static infoBox displays fixed data, ideal for constants or baseline metrics.
Dynamic infoBox, enabled through infoBoxOutput and renderInfoBox, updates in response to user interactions or live data feeds.
Appearance Customization:
fill parameter alters the background fill.fill=FALSE (default) gives a cleaner look, while fill=TRUE provides a more pronounced, filled background.# Dashboard Body with infoBox examples
body = dashboardBody(
fluidRow(infoBox("New Users", 20, icon = icon("users")),
infoBoxOutput("learningBox")),
fluidRow(infoBox("New Users", 20, icon = icon("users"), fill = TRUE),
infoBoxOutput("learningBox2")),
fluidRow(box(width = 4, actionButton("count", "Increment progress"))))
server <- function(input, output) {output$learningBox <- renderInfoBox({
infoBox("Progress", paste0(25 + input$count, "%"), icon = icon("list"),
color = "orange")})
output$learningBox2 <- renderInfoBox({
infoBox("Progress", paste0(25 + input$count, "%"),
icon = icon("list"), color = "orange", fill = TRUE)})} valueBox, while similar in purpose to infoBox, offers a different aesthetic. It’s another way to present figures or indicators visually.Usage and Customization:
valueBox can be static or dynamic, suitable for various data presentation needs.infoBox, valueBox supports the fill parameter for background customisation.sidebar <- dashboardSidebar(
sliderInput("number", "Choose a number:", min= 1, max = 100, value = 50))
body <- dashboardBody(
fluidRow(valueBox(100, "Static Value",icon = icon("thumbs-up"),
color = "green"), valueBoxOutput("dynamicValueBox")))
server <- function(input, output) {
output$dynamicValueBox <- renderValueBox({
valueBox(input$number, "Dynamic Value", icon = icon("refresh"),
color = "blue")}) } 1.Free text
Collect small amounts of text with textInput(), passwords with passwordInput(), and paragraphs of text with textAreaInput().
To collect numeric values, create a constrained text box with numericInput() or a slider with sliderInput(). If you supply a length-2 numeric vector for the default value of sliderInput(), you get a “range” slider with two ends.
3. selectInput
selectInput() creates a drop-down menu.choice to "" to default to NA.multiple to TRUE, you can also make a select where users can choose multiple options.4. checkboxGroupInput
checkboxGroupInput().5. checkboxInput
checkboxInput().value is TRUE when checked and FALSE when not.sliderInput() allows you to choose numbers between a min and max value.6. radioButtons
radioButton() is a good interface.selected to a choice value or character(0) to start with no selection.7. dateInput
dateInput() or a range of two days with dateRangeInput(). These provide a convenient calendar picker, and additional arguments like datesdisabled and daysofweekdisabled allow you to restrict the set of valid inputs."yyyy-mm-dd" is the best because it sorts into chronological order. Don’t let me catch you storing dates like "m/d/yyyy".8. fileInput
fileInput().accept lets you limit this to certain file types, but some browsers can bypass this requirement, so it’s not fool-proof.Note that:
selected and not value().selected = character(0).Output are ways that the Shiny app can dynamically display information to the user.
Outputs in the UI create placeholders that are later filled by the server function.
Like inputs, outputs take a unique ID as their first argument: if your UI specification creates an output with ID “plot”, you’ll access it in the server function with output$plot.
Each output function on the front end is coupled with a render function in the back end.
There are three main types of output, corresponding to the three things you usually include in a report: text, tables, and plots.
The following sections show you the basics of the output functions on the front end, along with the corresponding render functions in the back end.
Text
textOutput() and fixed code and console output with verbatimTextOutput().
The two render functions which behave slightly differently:
renderText() combines the result into a single string, and is usually paired with textOutput()
renderPrint() prints the result, as if you were in an R console, and is usually paired with verbatimTextOutput().
You can display any type of R graphic (base, ggplot2, or otherwise) with plotOutput() and renderPlot():
y = .data[[input$y]] inside aes(), instead of just y = input$y.imageOutput() takes the same arguments as plotOutput().width and height as their defaults if you are going to set those values in the render function.renderImage() needs to return a named list with at least an src with the image path.width and height (numeric values are in pixels), class and alt (the alt-text for screen readers).The deleteFile argument is currently optional, but triggers periodic warnings that it won’t be optional in the future.
You should set it to TRUE if you’re making a temporary file (this stops unneeded plots using memory) and FALSE if you’re referencing a file you previously saved.
There are two options for displaying data frames in tables:
tableOutput() and renderTable() render a static table of data, showing all the data at once.
dataTableOutput() and renderDataTable() render a dynamic table, showing a fixed number of rows along with controls to change which rows are visible.
tableOutput() is most useful for small, fixed summaries (e.g. model coefficients);
dataTableOutput() is most appropriate if you want to expose a complete data frame to the user.
If you have a long table to show, or one that you want users to be able to sort or search, use DT::dataTableOutput() (or its synonym DTOutput()).
The basic shiny package has dataTableOutput() and renderDataTable() functions, but they can be buggy.
The versions in the DT package are better and have many additional functions, so I use those.
renderDataTable() (or its synonym renderDT()).10.uiOutput().renderUI() to return HTML created.htmlOutput() is a synonym for uiOutput(), so you might see that in some code examples, but I use uiOutput() to make the connection with renderUI() clearer, since there is no renderHTML().