How do I structure the layout of my shiny dashboard?

I am creating a simple shiny app, and would love to structure my app in a certain way. See screenshot below -

Some things to highlight -

  1. The solid line below the value boxes
  2. In 3 sections with the sales map, sales trend plot and bar plot, is it possible to have a title for those sections, along with an info action button which I'll use to provide more info about the chart?

I am able to create the sidebar and value boxes with the code below, however I have trouble understanding how to use columns and/or boxes "below" the value boxes. See code below -

library(shiny)
library(shinydashboard)

# UI ----
ui <- navbarPage(
    useShinydashboard(),
    
    title = "My App",
    tabPanel(
        "Tab1", icon = icon("home"),
        fluidPage(
            sidebarLayout(
                sidebarPanel(
                    width = 2,
                    dateRangeInput(inputId   = "date_range",
                                   label     = h4("Date Range"),
                                   start     = as.Date("2018-01-01"),
                                   end       = as.Date("2020-12-31"),
                                   min       = as.Date("2018-01-01"),
                                   max       = as.Date("2020-12-31"),
                                   startview = "year"
                    )
                ),
                
                mainPanel(
                    # Value Box 1
                    valueBoxOutput(outputId = "box_1", width = 3),
                    
                    # Value Box 2
                    valueBoxOutput(outputId = "box_2", width = 3),
                    
                    # Value Box 3
                    valueBoxOutput(outputId = "box_3", width = 3),
                    
                    # Value Box 4
                    valueBoxOutput(outputId = "box_4", width = 3),
                    
                    br(),
                    hr()
                )
            )
        )
    )
)

# Server ----
server <- function(input, output) {

    # Box 1
    output$box_1 <- shinydashboard::renderValueBox({
        valueBox(5, "box1", color = "green"
        )
    })
    
    # Box 2
    output$box_2 <- renderValueBox({
        valueBox(10, "box2", color = "blue"
        )
    })
    
    # Box 3
    output$box_3 <- renderValueBox({
        valueBox(15, "box1", color = "purple"
        )
    })
    
    # Box 4
    output$box_4 <- renderValueBox({
        valueBox(20, "box1", color = "orange"
        )
    })
}

# Run the application 
shinyApp(ui = ui, server = server)


Below is one way to create your desired layout, which introduces fluidRow() and column() elements. Extra spacing and CSS (via style) were added for illustration purposes.

library(shiny)
library(shinydashboard)
library(tidyverse)

# UI ----
ui <- navbarPage(
  shinyWidgets::useShinydashboard(),
  
  title = "My App",
  tabPanel(
    "Tab1", icon = icon("home"),
    fluidPage(
      sidebarLayout(
        sidebarPanel(
          width = 2,
          dateRangeInput(inputId   = "date_range",
                         label     = h4("Date Range"),
                         start     = as.Date("2018-01-01"),
                         end       = as.Date("2020-12-31"),
                         min       = as.Date("2018-01-01"),
                         max       = as.Date("2020-12-31"),
                         startview = "year"
                         ),
          # create extra vertical space in sidebar (for illustration only)
          HTML(rep('<br>', 30))
        ),
        
        mainPanel(
          # 1st fluid row for value boxes
          fluidRow(
            # Value Box 1
            valueBoxOutput(outputId = "box_1", width = 3),
            
            # Value Box 2
            valueBoxOutput(outputId = "box_2", width = 3),
            
            # Value Box 3
            valueBoxOutput(outputId = "box_3", width = 3),
            
            # Value Box 4
            valueBoxOutput(outputId = "box_4", width = 3)
          ),
          br(),
          hr(),
          
          # 2nd fluid row for map and plots
          fluidRow(
            
            # 1st column for map
            column(6, style = 'border: 1px solid lightgrey; border-radius: 25px',
                   br(),
                   # ntitle and info button
                   div(HTML('<b>Sales Map Here</b> '), style = 'display: inline-block;'),
                   uiOutput('sales_map_button', style = 'display: inline-block;'),
                   br(), br(),
                   # map plot
                   plotOutput('sales_map'),
                   br(), br(), br()
                   ),
            
            # 2nd column for plots
            column(6, 
                   # fluidRow for sales trend
                   fluidRow(style = 'border: 1px solid lightgrey; border-radius: 25px; margin-left: 10px; padding-left: 10px;',
                            br(),
                            # sales trend title and info button
                            div(HTML('<b>Sales Trend Here</b> '), style = 'display: inline-block;'),
                            uiOutput('sales_trend_button', style = 'display: inline-block;'),
                            br(), br(),
                            # trend plot
                            plotOutput('trend_plot', height = '175px')
                            ),
                   br(),
                   # fluidRow for bar plot
                   fluidRow(style = 'border: 1px solid lightgrey; border-radius: 25px; margin-left: 10px; padding-left: 10px;',
                            br(),
                            # bar plot title and info button
                            div(HTML('<b>Bar Plot Here</b> '), style = 'display: inline-block;'),
                            uiOutput('bar_plot_button', style = 'display: inline-block;'),
                            br(), br(),
                            # bar plot
                            plotOutput('bar_plot', height = '175px')
                            )
                   )
          )
        )
      )
    )
  )
)

# Server ----
server <- function(input, output) {
  
  # Box 1
  output$box_1 <- shinydashboard::renderValueBox({
    valueBox(5, "box1", color = "green"
    )
  })
  
  # Box 2
  output$box_2 <- renderValueBox({
    valueBox(10, "box2", color = "blue"
    )
  })
  
  # Box 3
  output$box_3 <- renderValueBox({
    valueBox(15, "box1", color = "purple"
    )
  })
  
  # Box 4
  output$box_4 <- renderValueBox({
    valueBox(20, "box1", color = "orange"
    )
  })
  
  # sales map button
  output$sales_map_button <- renderUI({
    actionButton('salesMapButton', NULL, icon = icon('info'), style = 'border-radius: 50%;')
  })
  
  # sales map
  output$sales_map = renderPlot({
    ggplot(mtcars, aes(x = disp, y = mpg)) + geom_point()
  })
  
  # sales trend button
  output$sales_trend_button <- renderUI({
    actionButton('salesTrendButton', NULL, icon = icon('info'), style = 'border-radius: 50%;')
  })
  
  # sales trend plot
  output$trend_plot = renderPlot({
    ggplot(mtcars, aes(x = disp, y = mpg, group = 'cyl')) + geom_line()
  })
  
  # bar plot button
  output$bar_plot_button <- renderUI({
    actionButton('barPlotButton', NULL, icon = icon('info'), style = 'border-radius: 50%;')
  })
  
  # bar plot
  output$bar_plot = renderPlot({
    ggplot(count(mtcars, cyl), aes(x = cyl, y = n)) + geom_bar(stat = 'identity')
  })
}

# Run the application 
shinyApp(ui = ui, server = server)

Here is the result.

@scottyd22 Amazing. Do you know how i can adjust the value boxes width to fill up the page? they currently have a width of 3. Increasing that to 4 pushes one box to the next line. Also setting the width to 3.5 dosen't seem to work too.

You can set the mainPanel width to fill up the page.

mainPanel(width = 10,
          ...

If you don't want the plots to extend all the way, change the column width.

column(width = 5, ...

@scottyd22 Thank you.

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.

If you have a query related to it or one of the replies, start a new topic and refer back with a link.