Themes

Easily customize the look of Shiny apps and R Markdown documents with the bslib and thematic packages.
Author

Carson Sievert

Published

January 11, 2024

Shiny v1.6 and higher integrates with the {bslib} package providing easy access to modern versions of Bootstrap, Bootswatch themes, as well as custom themes that can even be modified in real time!

Using bslib in Shiny

To use {bslib} in your own Shiny app, pass a bs_theme() object to the theme argument of the relevant page layout function, such as page_navbar() or page_fillable(). Inside bs_theme(), you can specify a version of Bootstrap and (optionally) a Bootswatch theme (e.g. minty)

library(shiny)
library(bslib)

ui <- page_navbar(
  theme = bs_theme(version = 5, bootswatch = "minty"),
  ...
)

A Shiny app with Bootswatch's minty theme.

While Bootswatch themes make it very easy to change the default look of an application, you may want to design your own custom theme. In this case, {bslib}’s custom theming options make this much easier than writing custom CSS.

Custom themes

The bs_theme() function provides direct access to Bootstrap’s main colors & fonts as well as any of the 100s of more specific theming options. Also, when it comes to custom font(s) that may not be available on the end users machine, make sure to leverage {bslib}’s helper functions like font_google(), font_link(), and font_face(), which assist in including font file(s) in an convenient, efficient, and responsible way.

library(bslib)
theme <- bs_theme(
  bg = "#0b3d91", fg = "white", primary = "#FCC780",
  base_font = font_google("Space Mono"),
  code_font = font_google("Space Mono")
)
bs_theme_preview(theme)

A Shiny app with a Material dark mode look.

The main reason why {bslib} makes it so much easier to implement custom themes is that bs_theme() leverages Bootstrap Sass variables, allowing you to change only a few color(s) and font(s) to impact potentially hundreds of Bootstrap’s CSS rules. Also, thanks to CSS Utility Classes, you can now more easily tackle complicated UI issues that Sass variables alone can’t solve such as adjustments to spacing, alignment, borders, background colors, and more. To learn more about leveraging {bslib} to tackle more custom theming tasks, see the article on custom theming.

And while a lot of custom theming can be done via bs_theme() (i.e., CSS), it fundamentally can’t effect renderPlot(), because the image is rendered by R, not by the web browser. To help solve this problem, we’ve also created the {thematic} package which can effectively translate CSS to new R plotting defaults by just calling thematic::thematic_shiny() before running an app.

A ggplot2 plot with default R styling A ggplot2 plot with default styling defaults informed by CSS

This ‘auto theming’ behavior that {thematic} provides works great in Shiny with any CSS framework (not just {bslib}). Also, more generally, {thematic} can help simplify plot theming inside any R environment, using any graphics device, and also makes it super easy to use Google Fonts inside your R plots.

Real-time theming

The {bslib} package also provides an interactive theming widget that you can use to theme any Shiny app in real-time, or any rmarkdown::html_document that uses runtime: shiny. To use it in your own Shiny app, call bs_themer() inside your server function with a UI that uses Bootstrap 4 (or higher).

library(shiny)
library(bslib)
thematic::thematic_shiny(font = "auto")

ui <- fluidPage(
  theme = bs_theme(),
  ...
)

server <- function(input, output) {
  bs_themer()
  
  ...
}

shinyApp(ui, server)

If you want the real-time theming changes to effect static R plots, make sure {thematic} auto-theming is enabled, and that plots are generated with renderPlot()

---
runtime: shiny
output:
  html_document:
    theme: !expr bslib::bs_theme()
---

```{r, echo = FALSE}
bslib::bs_themer()
thematic::thematic_shiny(font = "auto")
```

# Here's a plot

Make sure to use `renderPlot()` if you want R plots to respond to real-time theming!

```{r}
renderPlot({
  plot(pressure)
})
```

Custom real-time theming

Shiny 1.6 introduced session$setCurrentTheme() and session$getCurrentTheme() session methods for dynamically updating the Bootstrap theme after initial load. These methods power bs_themer(), but they can also be used to implement custom real-time theming widgets like a dark mode switch.

Learn more

To learn more about the {bslib} and {thematic} packages, see https://rstudio.github.io/bslib/articles/theming/index.html and https://rstudio.github.io/thematic