Themes

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

Carson Sievert

Published

February 1, 2021

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 navbarPage() or fluidPage(). Inside bs_theme(), you can specify a version of Bootstrap and (optionally) a Bootswatch theme (e.g. minty)

library(shiny)
library(bslib)

ui <- fluidPage(
  theme = bs_theme(version = 4, 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)
```

<img src="custom-theme.png" alt="A Shiny app with a Material dark mode look." width="100%" style="border: 1px solid #ddd; box-shadow:5px 5px 5px #eee;"/>

The main reason why `{bslib}` makes it so much easier to implement custom themes is that `bs_theme()` leverages [Bootstrap Sass variables](https://rstudio.github.io/bslib/articles/bs4-variables.html), 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](https://rstudio.github.io/bslib/articles/utility-classes.html), 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](https://rstudio.github.io/bslib/articles/bslib.html#custom-themes).

And while a lot of custom theming can be done via `bs_theme()` (i.e., CSS), it fundamentally can't effect [`renderPlot()`](/r/reference/shiny/latest/renderPlot.html), because the image is rendered by R, not by the web browser. To help solve this problem, we've also created the [`{thematic}` package](https://rstudio.github.io/thematic/) which can effectively translate CSS to new R plotting defaults by just calling [`thematic::thematic_shiny()`](https://rstudio.github.io/thematic/reference/thematic_on.html) before running an app.

<div align="center">
  <img src="thematic-before.png" alt="A ggplot2 plot with default R styling" width="80%" style='border: 1px solid #ddd; box-shadow:5px 5px 5px #eee;'/>
  <img src="thematic-after.png" alt="A ggplot2 plot with default styling defaults informed by CSS" width="80%" style='border: 1px solid #ddd; box-shadow:5px 5px 5px #eee;'/>
</div>

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](https://fonts.google.com/) inside your R plots.


## Real-time theming {#real-time}

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

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

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

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

shinyApp(ui, server)

By the way, bs_themer() also works with html_documents + runtime: shiny. As above, 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 setCurrentTheme() and 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 and https://rstudio.github.io/thematic