The hardware and bandwidth for this mirror is donated by METANET, the Webhosting and Full Service-Cloud Provider.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]metanet.ch.

Theming and light/dark

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.

Client helpers

window.shinyglass.setPreset("dark"); // or "light" / "auto"
window.shinyglass.getPreset();       // resolved "light" | "dark"
window.shinyglass.getMode();         // requested mode incl. "auto"
window.shinyglass.setTint(false);
window.shinyglass.setPrimary("#AF52DE");
window.shinyglass.getPrimary();

Teal

options(teal.bs_theme = glass_theme(preset = "auto"))
# then teal::init(...) as usual

Reduced motion

When the user prefers reduced motion (prefers-reduced-motion: reduce):

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.

These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.