bslibdash ships a single brand theme,
[brand_bs_theme()], that every page constructor applies by
default. This vignette shows how to use it as-is, tweak individual
Bootstrap variables, add your own SCSS, swap to a different Bootswatch
preset, and tune the theme interactively with
bslib::bs_themer().
For the building blocks underneath, see the bslib theming articles.
The default theme
brand_bs_theme() returns a
bslib::bs_theme() built on Bootstrap 5
(bootswatch = "bootstrap") with the bslibdash brand colour
and typography defaults. Component CSS is not baked into the theme -
each bslibdash component attaches its own theme-aware SCSS via
bslib::bs_dependency_defer(), so swapping
theme does not drop bslibdash styles. Key variable
defaults:
| Variable | Value |
|---|---|
primary |
#0460A9 |
body-color |
#111827 |
border-radius |
.75rem |
font-family |
System UI stack |
enable-shadows |
TRUE (subtle, layered) |
Overriding theme variables
Use bslib::bs_add_variables() to override individual
Bootstrap Sass variables and pass the result to any page
constructor:
library(shiny)
library(bslibdash)
theme <- brand_bs_theme() |>
bslib::bs_add_variables(
primary = "#8B0000",
`body-color` = "#1F2937",
`font-size-base` = "0.95rem"
)
ui <- dashboardPage(
header = dashboardHeader(title = "Maroon dashboard"),
sidebar = dashboardSidebar(),
body = dashboardBody(),
theme = theme
)Component status colours (primary, success,
…) automatically pick up the new variable values, so cards, buttons,
badges and value boxes re-skin together.
Adding custom SCSS
Add bespoke rules with bslib::bs_add_rules():
theme <- brand_bs_theme() |>
bslib::bs_add_rules("
.app-header { background: linear-gradient(90deg, #0460A9, #003a6e); }
.app-footer { font-size: 0.85rem; }
")Switching the Bootswatch preset
theme <- bslib::bs_theme(version = 5, bootswatch = "flatly") |>
bslib::bs_add_variables(primary = "#0460A9")
dashboardPage(
header = dashboardHeader(title = "Flatly + brand blue"),
sidebar = dashboardSidebar(),
body = dashboardBody(h2("Flatly + brand blue")),
theme = theme
)Note: bslibdash component CSS is attached by the components
themselves, so any bslib::bs_theme() - including a plain
bslib::bs_theme(version = 5) - still renders the package’s
custom classes (.bslibdash-value-box,
.bslibdash-info-box, .app-sidebar, …). Use
brand_bs_theme() when you want the bslibdash brand
defaults; use your own bs_theme() when you do not.
Real-time theming
bslib::bs_themer() works against bslibdash pages out of
the box - call it once from your server to interactively tune colours
and typography during development:
server <- function(input, output, session) {
bslib::bs_themer()
}See the bslib real-time theming article for the underlying widget.
Dynamic theming
session$setCurrentTheme() swaps the active
bs_theme() at runtime without a page reload, which makes it
easy to let users flip between light/dark variants or any other named
presets. Because each bslibdash component attaches its SCSS via
bslib::bs_dependency_defer(), the components automatically
recompile against the new theme:
library(shiny)
library(bslib)
library(bslibdash)
themes <- list(
light = brand_bs_theme(),
dark = bs_theme(
version = 5,
bg = "#0B0F19",
fg = "#E5E7EB",
primary = "#60A5FA"
)
)
ui <- dashboardPage(
title = "Theme switcher",
header = dashboardHeader(
rightUi = radioButtons(
"mode", NULL,
choices = c("light", "dark"),
inline = TRUE
)
),
sidebar = dashboardSidebar(
sidebarMenu(
id = "sidebar",
menuItem("Overview", tabName = "overview", icon = icon("house"))
)
),
body = dashboardBody(
fluidRow(
valueBox(1200, "Total sales", icon = icon("graph-up"), color = "success"),
valueBox(53, "Open issues", icon = icon("exclamation-triangle"), color = "warning"),
valueBox(8, "Critical alerts", icon = icon("bell"), color = "danger")
),
fluidRow(
infoBox(title = "CPU usage", value = "48%",
subtitle = "Average over last 5 min",
icon = icon("cpu"), color = "primary"),
infoBox(title = "Queue length", value = 17,
subtitle = "Waiting jobs",
icon = icon("inboxes"), color = "warning")
),
fluidRow(
box(title = "Status", width = 6, status = "primary",
"All systems nominal."),
box(title = "Notes", width = 6, status = "info",
collapsible = TRUE,
"Toggle between light and dark in the header to see the theme swap.")
)
),
theme = themes$light
)
server <- function(input, output, session) {
observeEvent(input$mode, {
session$setCurrentTheme(themes[[input$mode]])
})
}
shinyApp(ui, server)Use the same pattern to expose any other curated set of presets (for
example, a Bootswatch picker) - just build the bs_theme()
objects ahead of time and hand the chosen one to
setCurrentTheme(). The dark variant above is built with
bs_theme(bg = ..., fg = ..., primary = ...) rather than
bs_add_variables() on the brand theme because the former
makes bslib rederive a coherent palette (greys, borders, link colours,
secondary/tertiary backgrounds) from bg/fg,
while the latter only patches the named variables. For the underlying
mechanics, see ?bslib::bs_dependency_defer.
