Basics
library(shiny)
library(shinyglass)
ui <- fluidPage(
theme = glass_theme(), # or preset = "dark" / "auto"
titlePanel("Liquid Glass"),
plotOutput("p")
)glass_theme() returns a bslib theme.
Pass it as theme = to fluidPage(),
navbarPage(), bslib::page_sidebar(), and other
page helpers that accept a bslib theme.
Presets
preset |
Behavior |
|---|---|
"light" |
Light glass pack (default) |
"dark" |
Dark glass pack |
"auto" |
Follows prefers-color-scheme; updates when the OS theme
changes |
Light and dark surface tokens ship as dual CSS custom-property packs
on [data-glass-preset]. Switching preset updates
document.documentElement.dataset.glassPreset — no Sass
recompile and no full page reload.
Runtime updates from the server
ui <- fluidPage(
theme = glass_theme(preset = "auto"),
glass_theme_toggle(selected = "auto"),
selectInput("accent", "Accent", c(
Blue = "#007AFF", Purple = "#AF52DE", Orange = "#FF9500"
))
)
server <- function(input, output, session) {
observe_glass_theme_toggle(input, session)
observeEvent(input$accent, {
update_glass_theme(session, primary = input$accent)
}, ignoreInit = TRUE)
}update_glass_theme() accepts:
| Argument | Effect |
|---|---|
preset |
"light" / "dark" /
"auto"
|
tint |
Content-aware ambient color from plots/images |
primary |
Live accent via CSS variables (--bs-primary, …) |
primary updates Bootstrap accent CSS variables so
buttons, checked controls, and other accent surfaces follow without a
reload. A few Sass-baked one-offs may still need a full reload to pick
up a new color.
Theme toggle helper
ui <- fluidPage(
theme = glass_theme(preset = "auto"),
glass_theme_toggle(), # Light / Dark / Auto buttons
# ...
)
server <- function(input, output, session) {
observe_glass_theme_toggle(input, session)
}Buttons call window.shinyglass.setPreset() immediately
and also fire Shiny inputs (glass_toggle_light, …) so the
server can stay in sync.
Behavior knobs
glass_theme(
preset = "auto",
primary = "#AF52DE",
blur = 36,
saturation = 200,
radius = "1.5rem",
material = "regular", # or "clear" over media-rich content
intensity = 0.45, # 0 Ultra Clear → 1 Tinted (iOS 27)
tint = TRUE, # sample plot/image colors into glass surfaces
specular = TRUE, # pointer specular highlight
nav_morph = TRUE # compact navbar while scrolling down
)material = "regular" is the adaptive Tahoe-style fill
(default). Use "clear" when chrome sits over rich media and
labels stay bold.
Use [glass_intensity_slider()] for a live Ultra Clear → Tinted control (same idea as iOS 27 Settings → Appearance → Liquid Glass):
glass_intensity_slider("glass_intensity", value = 0.45)All three JS behaviors default to TRUE (same as 0.1.x).
They respect prefers-reduced-motion: reduce where relevant.
Advanced escape hatch:
window.__shinyglassDisableTint = true still disables
tint.
CSS variables (migration from 0.1.x)
Breaking in 0.2.0: light/dark surfaces are dual CSS
packs, not a Bootswatch darkly rebuild. Prefer CSS custom
properties over Sass $glass-* tokens when customizing:
:root {
/* shared knobs also set by glass_theme(blur=..., radius=...) */
--glass-blur: 36px;
--glass-radius: 1.25rem;
--bs-primary: #007AFF; /* also updated by update_glass_theme(primary=) */
--glass-primary: #007AFF;
}
:root[data-glass-preset="dark"] {
/* override a dark-pack value if needed */
--glass-bg: rgba(255, 255, 255, 0.1);
}Apps that overrode Sass-only $glass-* tokens should
target --glass-* or [data-glass-preset="dark"]
instead.
Teal
options(teal.bs_theme = glass_theme(preset = "auto"))
# then teal::init(...) as usualReduced motion
When the user prefers reduced motion
(prefers-reduced-motion: reduce):
- Navbar morph transforms are disabled (JS + CSS)
- Pointer specular tracking is skipped
- Content tint sampling is skipped
- Decorative transitions on cards/inputs/nav are removed
This is automatic — no app code required.
Active-on-accent contrast
Bootstrap’s color-contrast() often picks
black ink for system blue #007AFF.
glass_theme() forces light ink on primary fills so checked
checkboxes, radios, switches, and active pagination stay readable.