Skip to contents

Create a bslib::bs_theme() styled with a Liquid Glass look: translucent surfaces, backdrop blur, soft depth, and system typography. Pass the result to theme = on fluidPage(), navbarPage(), bslib::page_sidebar(), or any other page function that accepts a bslib theme. For a shinyreact client, use glass_page_react() so the theme is passed as theme (an unnamed theme is not enough: shinyreact would suppress Bootstrap and drop this CSS).

Usage

glass_theme(
  preset = c("light", "dark", "auto"),
  primary = "#007AFF",
  blur = 36,
  saturation = 200,
  radius = "1.5rem",
  material = c("regular", "clear"),
  plot_surface = c("clear", "opaque"),
  intensity = 0.5,
  tint = TRUE,
  specular = TRUE,
  nav_morph = TRUE,
  ambient_motion = TRUE,
  persist = FALSE,
  scene = c("default", "tahoe", "dusk", "mesh", "aurora", "harbor", "grove"),
  wallpaper = NULL,
  flatten = FALSE,
  tokens = NULL,
  refraction = TRUE,
  morph = TRUE,
  press = TRUE,
  scroll_edge = TRUE,
  minimize_tabs = TRUE,
  icon_style = c("clear", "color", "all"),
  floating_sidebar = FALSE,
  ...
)

Arguments

preset

"light", "dark", or "auto". "auto" follows prefers-color-scheme and updates when the OS theme changes.

primary

Accent color for buttons, links, and focus rings. Defaults to system blue (#007AFF).

blur

Backdrop blur radius in pixels. Default 36 matches the iOS 27 diffusion-first material.

saturation

Backdrop saturation percentage. Default 200.

radius

Default border radius for glass surfaces (CSS length). Prefer larger concentric radii (default 1.5rem).

material

"regular" (adaptive, most UI). "clear" is deprecated and maps to a low intensity (0.12) when intensity is omitted, so older apps stay clearer than the midpoint. Prefer intensity.

plot_surface

"clear" (default) keeps plot/table hosts translucent so wallpaper shows through. "opaque" densifies .shiny-plot-output, plotly, gt, and DT hosts (~94% panel fill, readable ink) while leaving nav and controls on Liquid Glass. Also available as the CSS class .glass-plot-surface-opaque on a host or ancestor.

intensity

Liquid Glass intensity from 0 (Ultra Clear) to 1 (Tinted), matching iOS 27 Settings -> Appearance -> Liquid Glass. Default 0.5 (Apple's midpoint). The web cannot read the OS slider; use glass_intensity_slider() for the in-app control. Reduce Transparency and Increase Contrast override the painted glass.

tint

Logical. Content-aware ambient tint from plots and images. Default TRUE.

specular

Static top and bottom specular highlights. iOS 27 does not follow the pointer or device tilt. FALSE hides the highlights.

nav_morph

Logical. Compact navbar on scroll down; expand on scroll up. Default TRUE.

ambient_motion

Logical. Animate the decorative ambient sheen. Default TRUE. Set FALSE to keep static glass surfaces. OS reduced-motion settings take priority.

persist

Remember preset, intensity, accent, material, plot surface, and scene in localStorage for this app path. Default FALSE (opt in). glass_page() turns this on.

scene

Wallpaper scene id from glass_scenes() ("default", "tahoe", "dusk", "mesh", "aurora", "harbor", "grove").

wallpaper

Optional image URL painted as a frosted photo behind the glass (https, data URI, or site-relative path). Photos are blurred and washed so body ink stays above the contrast floor (see glass_css_tokens()).

flatten

TRUE starts in print/export flatten mode (no backdrop blur). See glass_flatten().

tokens

Named list of public CSS token overrides (see glass_css_tokens() / glass_add_tokens()).

refraction

TRUE (default) bends the backdrop through a convex squircle lens in Chromium (backdrop-filter: url() plus an SVG displacement map, index of refraction about 1.5). Safari and Firefox keep the blur and tint. Reduced transparency, increased contrast, forced colors, and flatten mode turn the lens off.

morph

TRUE (default) springs an active indicator between items in the same group (nav pills, tabs, button groups, the theme toggle) and scales menus and popovers out of their trigger. Click targets stay on the original controls.

press

TRUE (default) scales and slightly rotates glass buttons and nav links while pressed, then springs back. Reduced motion skips it.

scroll_edge

TRUE (default) lays a uniform toolbar backing and edge fade over floating bars while content scrolls underneath.

minimize_tabs

TRUE (default) shrinks top and bottom tab bars and nav pills while scrolling down, and expands them on scroll up or interaction. Reduced motion keeps them full size.

icon_style

"clear" (default) paints icons in nav bars, tab bars, and non-primary buttons as monochrome glass ink: #1d1d1f in light mode (a white glyph would fail the contrast floor) and near-white in dark mode. "color" leaves author colors. "all" also restyles icons inside cards, still skipping solid accent buttons.

floating_sidebar

FALSE (default). TRUE detaches bslib and .glass-sidebar panels into a rounded glass card with margin (iPadOS 26 style). Off by default so existing layouts keep their docked sidebar.

...

Additional arguments forwarded to bslib::bs_theme().

Value

A bslib::bs_theme() object suitable for 'shiny' page functions.

Details

Light and dark surface tokens are compiled into dual CSS custom-property packs. Switching preset at runtime (via update_glass_theme() or preset = "auto") updates document.documentElement.dataset.glassPreset without recompiling Sass or reloading the page. Accent color can also be updated live with update_glass_theme() primary= (CSS variables).

Examples

theme <- glass_theme()
opaque <- glass_theme(
  plot_surface = "opaque",
  scene = "aurora",
  tokens = list(blur = "28px")
)

if (interactive()) {
  library(shiny)

  ui <- fluidPage(
    theme = glass_theme(preset = "auto"),
    titlePanel("Liquid Glass"),
    glass_theme_toggle(),
    selectInput("color", "Color", c("Blue", "Purple", "Orange")),
    plotOutput("plot")
  )

  server <- function(input, output, session) {
    # Client onclick already switches; keep session in sync:
    observe_glass_theme_toggle(input, session)
  }

  shinyApp(ui, server)
}