Back to Tutorials
Expo SDK 56

Build a Liquid Glass UI with Expo GlassEffect

expo-glass-effect gives Expo apps access to native Liquid Glass-style surfaces. Here is a practical way to use it without pretending every platform can render the same effect.

June 16, 2026 10 min read Paddy B
Expo GlassEffect Expo SDK 56 React Native iOS 26 Liquid Glass

The short version

Use expo-glass-effect for carefully scoped iOS Liquid Glass surfaces: headers, cards, floating controls, and compact panels. Guard it at runtime and ship a normal React Native fallback for Android, web, older iOS, and accessibility settings.

The important caveat is support. Expo documents GlassView as available on iOS 26 and above, with a fallback to a regular View on unsupported platforms. That makes it exciting, but not something to wrap your whole app in without checks.

What GlassEffect is

expo-glass-effect exposes React components that render a glass effect using iOS native visual effect APIs. In practice, that means you can create UI that feels like the new system glass language instead of faking it with translucent views and blur hacks.

The package is bundled with Expo SDK 56 and is included in Expo Go, so it is easy to try. The production decision is less casual: this is a platform feature with platform limits, and those limits should be visible in your component design.

Use it as an enhancement

Treat glass as progressive enhancement. The app should remain readable and usable when the glass API is missing, reduced, or intentionally disabled.

1. Install GlassEffect

Install the package through Expo so the native package version matches your SDK.

npx expo install expo-glass-effect

If you are starting from scratch, create an Expo app first, then install the package.

npx create-expo-app@latest glass-demo cd glass-demo npx expo install expo-glass-effect

2. Create a safe glass wrapper

Start with a wrapper that can decide whether to render GlassView or a normal View. This keeps the risky checks in one place instead of spreading platform conditions through every screen.

import { useEffect, useState } from "react"; import { AccessibilityInfo, Platform, StyleSheet, View } from "react-native"; import { GlassView, isGlassEffectAPIAvailable, isLiquidGlassAvailable, } from "expo-glass-effect"; export function useCanRenderGlass() { const [canRenderGlass, setCanRenderGlass] = useState(false); useEffect(() => { let mounted = true; async function checkSupport() { const reduceTransparency = await AccessibilityInfo.isReduceTransparencyEnabled(); const supported = Platform.OS === "ios" && isGlassEffectAPIAvailable() && isLiquidGlassAvailable() && !reduceTransparency; if (mounted) { setCanRenderGlass(supported); } } checkSupport(); const subscription = AccessibilityInfo.addEventListener( "reduceTransparencyChanged", checkSupport ); return () => { mounted = false; subscription.remove(); }; }, []); return canRenderGlass; } export function SafeGlassPanel({ children, style }) { const canRenderGlass = useCanRenderGlass(); if (!canRenderGlass) { return <View style={[styles.fallbackPanel, style]}>{children}</View>; } return ( <GlassView style={[styles.glassPanel, style]} glassEffectStyle="regular" tintColor="rgba(255,255,255,0.22)" isInteractive> {children} </GlassView> ); } const styles = StyleSheet.create({ glassPanel: { borderRadius: 24, overflow: "hidden", padding: 18, }, fallbackPanel: { borderRadius: 24, padding: 18, backgroundColor: "rgba(15,23,42,0.86)", borderWidth: StyleSheet.hairlineWidth, borderColor: "rgba(255,255,255,0.18)", }, });

isGlassEffectAPIAvailable() is the crash-prevention check. Expo added it because some iOS 26 beta states may report Liquid Glass components while the underlying API is not safe to use. isLiquidGlassAvailable() tells you whether the app can use the Liquid Glass component family.

3. Build a practical glass header

Use the wrapper for a contained, high-impact surface. A header card is a good first target because it benefits from material depth, but the app still works if the fallback renders instead.

import { ImageBackground, StyleSheet, Text, View } from "react-native"; import { SafeGlassPanel } from "./SafeGlassPanel"; export function DestinationHeader() { return ( <ImageBackground source={require("../assets/coast.jpg")} style={styles.hero} imageStyle={styles.heroImage}> <View style={styles.overlay}> <SafeGlassPanel style={styles.card}> <Text style={styles.kicker}>Weekend plan</Text> <Text style={styles.title}>Galway coast walk</Text> <Text style={styles.body}> Native glass on supported iOS devices. Clear, readable fallback everywhere else. </Text> </SafeGlassPanel> </View> </ImageBackground> ); } const styles = StyleSheet.create({ hero: { minHeight: 360, justifyContent: "flex-end", }, heroImage: { borderRadius: 28, }, overlay: { padding: 20, }, card: { gap: 8, }, kicker: { color: "#a7f3d0", fontWeight: "800", textTransform: "uppercase", }, title: { color: "#ffffff", fontSize: 30, fontWeight: "800", }, body: { color: "rgba(255,255,255,0.84)", lineHeight: 22, }, });

Keep text contrast high. Glass is a background treatment, not a reason to make the content harder to read.

4. Group glass surfaces with GlassContainer

When multiple glass views sit near each other, wrap them in GlassContainer. That gives the native effect more context and keeps related glass surfaces behaving like a small system.

import { GlassContainer } from "expo-glass-effect"; import { StyleSheet, Text, View } from "react-native"; import { SafeGlassPanel, useCanRenderGlass } from "./SafeGlassPanel"; export function FloatingControls() { const Container = useCanRenderGlass() ? GlassContainer : View; return ( <Container style={styles.container}> <SafeGlassPanel style={styles.control}> <Text style={styles.value}>22C</Text> <Text style={styles.label}>Weather</Text> </SafeGlassPanel> <SafeGlassPanel style={styles.control}> <Text style={styles.value}>4.8 km</Text> <Text style={styles.label}>Route</Text> </SafeGlassPanel> </Container> ); } const styles = StyleSheet.create({ container: { flexDirection: "row", gap: 12, }, control: { minWidth: 120, }, value: { color: "#ffffff", fontSize: 22, fontWeight: "800", }, label: { color: "rgba(255,255,255,0.72)", }, });

The grouped container uses the same runtime guard. If glass is unavailable, the wrapper falls back to a normal View while the child panels keep their readable fallback styling.

5. Handle platform and accessibility fallbacks

A good fallback is not a dull afterthought. It should be part of the design. For unsupported platforms, render an opaque or lightly translucent card with a border. For users who reduce transparency, prefer clarity over decoration.

  • iOS 26+: render GlassView only after the runtime checks pass.
  • Older iOS: use the same layout with a readable fallback view.
  • Android and web: do not imply Liquid Glass support; use normal React Native styling.
  • Reduced transparency: respect the accessibility setting and avoid glass-heavy UI.

The production rule

Never gate critical actions behind a glass-only surface. If the effect disappears, the screen should still explain itself and every button should still be reachable.

Final checklist

  • Install with npx expo install expo-glass-effect.
  • Use GlassView for contained surfaces, not entire app shells.
  • Use GlassContainer when nearby glass surfaces should behave as a group.
  • Guard rendering with isGlassEffectAPIAvailable() and isLiquidGlassAvailable().
  • Respect AccessibilityInfo.isReduceTransparencyEnabled().
  • Test the fallback path on Android, web, older iOS, and reduced transparency settings.
Support tutorials