Glass Surface

A theme-level material preference selected by surface role and context: stable frost for reading/content panes, Liquid Glass for eligible functional surfaces, and inherited treatment for unfilled anatomy. <ThemeProvider glass> requests glass, <ThemeProvider solid> selects complete opaque appearance, and omitting both uses the platform default (glass on supported iOS 26+, solid elsewhere).

What 'glass' means in Canvas

Material, density, and motion are separate decisions. Reading panes, field wells, passive badges, and chart frames use stable frost. Functional floating shells and controls can use Liquid Glass where supported, with native feedback first. Labels, images, chart marks, layout wrappers, and unfilled variants inherit their host instead of gaining a pane. The kit's shared material rendering supplies the material; glass-tint, glass-tint-content, glass-tint-control, and glass-tint-dense control coverage without replacing semantic colors. A dense menu can remain Liquid Glass while keeping its rows legible. A liquid material names the surface, never a motion: nothing deforms, travels or springs.
Anatomy. Toggle with the Solid / Glass switch in the topbar, or pass the boolean to the provider: <ThemeProvider glass> forces glass, <ThemeProvider solid> forces flat, and omitting both picks the platform default (glass on iOS 26+ via liquidGlassAvailable(), solid elsewhere).
Component APIs stay the same. Shared rendering supplies native Liquid Glass where supported, Dark Factory’s plain frost on the web, and supported native blur elsewhere. Semantic card and popover colors stay opaque. Unavailable or unsafe material, Reduce Transparency, and Increase Contrast restore the complete solid appearance.

The four ingredients

Supported material combines a live backdrop, readable tint, and the platform skin's shape. The renderer keeps crisp content above it and restores the full solid skin when material is unavailable.

Blur material

Supported native Liquid Glass or native frost; the web uses a 24px plain backdrop blur.

Readable tint

The functional, content, control, and dense layers each have a tint chosen for their role.

The skin’s shape

Shared material rendering keeps the component’s radius and replaces its resting fill and border.

A safe live backdrop

The renderer samples content behind the surface without capturing itself. Text and icons remain crisp.

Surface inventory

Representative surfaced roles and tint density. The component variant and surrounding context determine whether a pane exists. Reading content remains still, functional surfaces use supported liquid material, and unfilled variants inherit. Density does not select motion.
Surface
Layer
Treatment
Navbar, Sidebar, Dialog, Drawer, Popover, Command
Functional
Supported glass with complete solid fallback
Card, list, table, calendar, chart, alert
Content
Stable frost for reading
Fields, buttons, tabs, chips, switches
Control
Role-appropriate material; bare variants stay bare
Option menus, AlertDialog, Toast, Tooltip
Dense
Denser tint for legibility; inverse surfaces retain inverse ink

Live comparison

A real Card and its controls under one ThemeProvider. Change the material and verify that the typed draft and checkbox state remain intact. The material falls back according to platform capabilities and accessibility preferences.
Request glass
The provider changes material while the form remains mounted.

Solid appearance

Available material follows the platform and accessibility settings.
Project name

When NOT to use glass

Use the complete solid appearance when the material cannot preserve readability, performance, or accessibility. A static content frame is appropriate only when its content remains clear.

Accessibility preferences

Reduce Transparency and Increase Contrast use a complete opaque appearance.

Unsupported material

A platform or capture configuration without safe blur falls back to solid.

Android page surfaces

Android frosts only what floats over a separate capture plane: overlays in an OverlayProvider outlet and sheets in a window of their own. A surface in the page itself has no plane it can sample without capturing itself, so with glass requested it keeps its complete solid skin, by design.

Unfilled variants

Layout wrappers and ghost or link actions inherit their surroundings without another pane.

Implementation

ThemeProvider carries the preference: pass glass or solid (glass wins if both are set), or omit both for the platform default reported by liquidGlassAvailable(). Shared rendering selects a supported material for each surfaced role, with complete opaque fallback when accessibility or capability requires it. Material changes preserve interaction state and native host identity. On the web, setSurface("glass") persists the choice and sets data-surface for the CSS handoff's material mode and page backdrop. Also pass the choice from getSurface() to ThemeProvider so React Native components follow it. CSS variables do not style native components.
tsx
// Request material through the provider.
<ThemeProvider glass>...</ThemeProvider>
<ThemeProvider solid>...</ThemeProvider>
// Keep the same tree when a user changes the preference.
<ThemeProvider glass={glass} solid={!glass}>
<Card><Input label="Project name" /></Card>
</ThemeProvider>