Modifying the shinydashboard theme with one line

R
Shiny
How to apply organizational/corporate themes to shinydashboard.
Author

Mauricio “Pachá” Vargas S.

Published

May 4, 2023

R and Shiny Training: If you find this blog to be interesting, please note that I offer personalized and group-based training sessions that may be reserved through Buy me a Coffee. Additionally, I provide training services in the Spanish language and am available to discuss means by which I may contribute to your Shiny project.

I’ve been using a customized ‘shinydashboard’ version since 2018, and some time ago I implemented changes to it that allowed me to use a custom CSS with one line changed in my R code. Originally I used some codes by @gadenbuie, and eventually I polished it.

One example is shiny.tradestatistics.io, a Shiny app that I’ve maintained for years and that won an honourable award in the Shiny Contest 2020.

The changes I made to the original ‘shinydashboard’ package are harmless, as these:

  1. Don’t alter the order of current arguments
  2. Add optional arguments that integrate with the existing code
  3. Don’t break dashboards running without custom CSS options

As an example, the aforementioned dashboard uses these simple changes:

  1. https://github.com/tradestatistics/visualization-with-shiny/blob/master/ui.R#L6-L7
  2. https://github.com/tradestatistics/visualization-with-shiny/blob/master/global.R#L129-L133

You can find a mimimal working example on GitHub. This example presents different customizations in the files ‘custom.css’ and ‘custom.min.css’ (I minified with ‘yui-compressor’). Among different options, you can copy the ‘skin-blue’ theme from my GitHub profile, put it in a new CSS inside ‘www/’, and from there adapt the colours and typographies to match those used by your organization or company.

A minimal structure, which you can modify by adapting the code from GitHub would be the next structure.

global.R

styles <- list(
  skin_color = "blue",
  css_files = c("css/AdminLTE.min.css", "css/_all-skins.min.css", "css/custom.min.css",
                "css/ion.rangeSlider.min.css")
)

app.R

library(shiny)
library(shinydashboard)

# Define UI for application that draws a histogram
ui <- dashboardPage(
    skin = "blue",
    theme = c("css/AdminLTE.min.css", "css/_all-skins.min.css", "css/custom.min.css",
              "css/ion.rangeSlider.min.css"),
    
    # Application title
    dashboardHeader(title = "Old Faithful Geyser Data"),
    
    ## Sidebar content
    dashboardSidebar(
        sidebarMenu(
            menuItem("Tab 1", tabName = "tab1", icon = icon("th"))
        )
    ),
    
    ## Body content
    dashboardBody(
        tabItems(
            # First tab content
            tabItem(tabName = "tab1",
                    fluidRow(
                        box(
                            title = "Controls",
                            # Sidebar with a slider input for number of bins 
                            sliderInput("bins", "Number of bins:", min = 1, max = 50,
                                        value = 30)
                        ),
                        
                        box(
                            # Show a plot of the generated distribution
                            plotOutput("plot1", height = 250)
                        )
                    )
            )
        )
    )
)

# Define server logic required to draw a histogram
server <- function(input, output) {
    
    output$plot1 <- renderPlot({
        # generate bins based on input$bins from ui.R
        x    <- faithful[, 2]
        bins <- seq(min(x), max(x), length.out = input$bins + 1)
        
        # draw the histogram with the specified number of bins
        hist(x, breaks = bins, col = 'darkgray', border = 'white')
    })
}

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

custom.css

@import url('https://fonts.googleapis.com/css2?family=Roboto+Slab:wght@700&family=Roboto:wght@400;700&display=swap');

* {
  font-family: 'Roboto', sans-serif;
}

/* H1 - H6 font */
h1, h2, .h1, .h2 {
  font-family: 'Roboto Slab', sans-serif;
  color: #2e87c8;
}

h3, h4, h5, h6, .h3, .h4, .h5, .h6 {
  font-family: 'Roboto Slab', sans-serif;
  color: #333333;
}

.sidebar {
  color: #333333;
}

.btn-icon-right {
  float: right !important;
  padding-top: 0.22em;
  padding-left: 0.25em;
}

.scroll-overflow-x {
  overflow-x: auto;
}

.irs-bar {
  border-top: 1px solid #333333;
  border-bottom: 1px solid #333333;
  background: #333333;
}

.irs-from, .irs-to, .irs-single {
  background: #333333;
}

#loading {
  position: fixed;
  width: calc(100% - 230px);
  height: 100vh;
  padding-top: 100px;
  text-align: center;
  font-size: 100%;
  color: #000000;
  background-color: #f2f2f2;
  z-index: 800;
}

.main-header .logo {
  font-family: 'Roboto Slab', sans-serif;
  font-weight: 700;
}