shinyreact apps do not render Shiny’s tag UI. The client is
www/ui.js, and shinyreact::page_react() drops
Bootstrap unless you pass theme.
glass_page_react() does that, and it also loads the Liquid
Glass React components so the client does not need its own glass
CSS.
library(shiny)
library(shinyreact)
library(shinyglass)
ui <- glass_page_react(
theme = glass_theme(preset = "auto", scene = "tahoe"),
title = "Liquid Glass"
)
server <- function(input, output, session) {
output$dist <- renderPlot({
pal <- glass_plot_colors(input = input)
hist(faithful$waiting, col = pal$fill, border = NA)
}, bg = "transparent")
}
shinyApp(ui, server)The matching www/ui.js reads the components from the
same global shinyreact already uses:
const { ReactDOM, useShinyInitialized, ShinyOutput } = window.shinyreact;
const {
useGlassTheme,
GlassPage,
GlassSidebar,
GlassSurface,
GlassButton
} = window.shinyglass;
const h = React.createElement;
function App() {
const ready = useShinyInitialized();
const theme = useGlassTheme();
if (!ready) return null;
return h(
GlassPage,
null,
h(
GlassSidebar,
null,
h(
GlassButton,
{
variant: theme.mode === "dark" ? "primary" : "secondary",
pressed: theme.mode === "dark",
onClick: () => theme.setMode(theme.mode === "dark" ? "light" : "dark")
},
theme.mode
)
),
h(GlassSurface, null, h(ShinyOutput, { id: "dist", className: "shiny-plot-output glass-plot" }))
);
}
ReactDOM.createRoot(document.body.appendChild(document.createElement("div"))).render(h(App));A full app ships at
system.file("examples/shinyreact-glass", package = "shinyglass").
It has no www/ui.css.
| Name | Element | Class |
|---|---|---|
GlassPage |
main |
.glass-page |
GlassMain |
div |
.glass-main |
GlassSidebar |
aside |
.glass-sidebar |
GlassSurface |
section |
.glass-surface |
GlassCard |
section |
.glass-surface.glass-card |
GlassStack |
div |
.glass-stack |
GlassButton |
button |
.glass-button-primary or
.glass-button-secondary |
GlassTitle |
h1 |
.glass-title |
GlassMuted |
p |
.glass-muted |
GlassRange |
input |
.glass-range |
GlassIntensitySlider |
div |
.glass-intensity-slider (Ultra Clear to Tinted, default
0.5) |
useGlassTheme() also reports refraction,
morph, press, scrollEdge,
minimizeTabs, iconStyle,
floatingSidebar, and reducedMotion. Setters
such as theme.setRefraction(false) and
theme.setIconStyle("color") call the same client API as
update_glass_theme(). GlassSidebar adds
.glass-sidebar-floating when floating is true
or the theme turned floating_sidebar on.
GlassButton takes variant
("primary" or "secondary") and
pressed. Primary fill follows --glass-accent /
--glass-on-primary. Secondary label ink follows
--glass-body-color. Sidebar, card, and page chrome use the
same surface tokens as bslib cards (blur, border, radius, shadow). Light
and dark packs swap those variables, so a button or panel written this
way tracks setPreset without a client stylesheet.
Plot and table hosts inside .glass-surface,
.glass-card, and .glass-sidebar stay
transparent, same as a plot inside .card. Ink for a base or
ggplot graphic is still drawn on the server. Use
glass_plot_colors(input = input) or
glass_resolved_preset(input) so the R graphic follows the
resolved pack. CSS variables are not available to the graphics
device.
The hook reads document.documentElement and subscribes
with a MutationObserver, so it sees the head script,
setPreset, and any other writer of the dataset.
| Field | Meaning |
|---|---|
mode |
"light", "dark", or
"auto" |
preset |
Resolved pack, "light" or "dark" |
scene |
Wallpaper scene |
material |
"regular" or "clear" ("clear"
is deprecated) |
intensity |
Number from 0 (ultra clear) to 1 (tinted). Default
0.5. |
reducedTransparency |
true when Reduce Transparency is on |
increasedContrast |
true when Increase Contrast is on |
forcedColors |
true when forced colors are active |
setMode, setScene,
setMaterial, and setIntensity call the
existing window.shinyglass mutators.
setMode("dark") is setPreset("dark").
setMaterial("clear") warns and maps to intensity
0.12. A later setIntensity() wins.
GlassIntensitySlider calls setIntensity and
labels the ends Ultra Clear and Tinted.
inst/js/shinyglass-react.js is an ES module attached as
the html dependency shinyglass-react (see
glass_react_dependency()). glass_page_react()
bundles it into the theme. bootstrapPage() emits theme
dependencies before www/ui.js, so the app module can
destructure window.shinyglass at top level. The file does
not touch window.shinyreact until a component renders,
because the theme module is earlier in the document than shinyreact’s
deferred script.
glass_theme_dependencies() appends the same dependency
for page_react_html(extra_deps = ). A plain
glass_theme() does not load it, so classic Shiny pages do
not download the React file.
page_react(theme = glass_theme()) still gets the CSS and
shiny-glass.js. Use glass_page_react(), or
pass glass_theme_dependencies(), when you want the
components.
This is not published as an npm package. shinyreact’s default app has
no build, and hooks must use the single React already on
window.shinyreact. A package that imported
react would load a second copy unless every app
externalized it. htmltools also serves the file at a versioned path, so
a hardcoded import in www/ui.js would break on each
shinyglass release. Named exports are there for a bundler
that can resolve the file itself. The supported no-build path is the
global, same as window.shinyreact.
Document class rules do not cross a shadow root.
--glass-* custom properties do. Call
window.shinyglass.adoptShadow(shadowRoot) from the
component that created the root. The example does this for a note inside
the page.