# Liquid glass in React Native and Expo (iOS 26, Android)

Source: https://meniscus.site/liquid-glass/react-native · Updated 2026-10-01

In React Native only iOS 26's native `GlassView` bends the backdrop; Android API 31 and later get blur, and reduced-transparency or older systems need an opaque surface. The hard part is choosing the right material per device and never calling frost refraction.

This is the React Native recipe the Meniscus MCP server gives coding agents: renderer versus target platform, material selection, tokens, platform behavior and acceptance.

Ask your assistant (with Meniscus connected): "Add a liquid glass tab bar to this Expo app for iOS and Android, with an honest fallback where glass is not available. Use the meniscus tools."

**In short:** Use the runnable `native/` Expo starter and React Native primitives; iOS 26 can use native GlassView after capability checks, Android API 31+ uses BlurTargetView with BlurView, and unavailable or reduced-transparency cases use an opaque surface. Android frost is not refraction.

**Limits:** only iOS 26 `GlassView` bends the backdrop, and the system draws that bend, so the px numbers are visual targets, not props. Android API 31+ and earlier iOS get blur (frost, no bend), everything else an opaque surface; never describe those as refraction. No effect shader (dispersion, caustics, iridescence, morph, liquid metal, border beam) is ported to React Native.

### Separate renderer from target platform

`web` means React DOM with HTML/CSS, browser SVG filters and WebGL. `react-native` means native View, Text,
Pressable, StyleSheet and native modules. React Native targets both Android and iOS; never infer iOS merely from
React or mobile. Request `create_design_brief` with medium `react-native` and platform `android`, `ios`, or
`android-ios`. Search references with renderer `react-native` to exclude web mockups in phone frames.

### Runnable source and installation

The starter is the React Native starter download on your Meniscus account page (paid plans); copy it (or the components you need) into your
project. It pins Expo SDK 55 and React Native 0.83.10 (Xcode 26 toolchain). In `native/`:

- `npm ci`, then `npm run typecheck` and `npm run test:material` (the material decision table).
- Expo Go: `npm start`, then `i` / `a`. Every native module the starter uses ships in Expo Go SDK 55.
- Native build: `npm run ios` / `npm run android` (`expo run:*`: prebuild, CocoaPods or Gradle, install). It needs
  Xcode or the Android SDK and a UTF-8 locale for CocoaPods (`LANG=en_US.UTF-8`).

A Metro bundle export is not a native build, and a web screenshot does not prove native support. `?theme=dark`,
`?page=overview|controls|forms` and `?dialog=1` in the app's deep link select a state for screenshots.

Shared implementations live in `native/src/components.tsx`: GlassButton, GlassIconButton, GlassCard, GlassBadge,
GlassAvatar, GlassSeparator, GlassSwitch, GlassCheckbox, GlassTabs, GlassProgress, GlassSlider, GlassStepper,
GlassTextField, GlassAccordion, GlassDialog and GlassTabBar. The weather widget is an in-app composition.
The remaining component specs are design guidance, not ready-made React Native exports. `get_platform_support`
reports the complete per-component coverage and verification record.

### Material selection

`native/src/material.ts` defines the capability decision, and `native/src/GlassSurface.tsx` renders it.

- iOS 26+: require both `isGlassEffectAPIAvailable()` and `isLiquidGlassAvailable()` before using `GlassView`.
  The native system controls refraction and highlights; the web pixel displacement values do not map one-to-one.
- Earlier supported iOS: use `BlurView` with a tint and rim; this branch is frost, not true refraction.
- Android API 31+: render the backdrop in `BlurTargetView` before the overlays, and pass its ref as `blurTarget`
  to `BlurView` using `blurMethod="dimezisBlurViewSdk31Plus"`. Keep the blur target outside its own overlays to
  avoid feedback. This provides blur only, not the iOS Liquid Glass effect.
- Earlier Android or missing blur target: choose an opaque material to retain contrast and predictable performance.
- Respect `AccessibilityInfo.isReduceTransparencyEnabled()` and its change event. Opaque fallback takes precedence.
- Avoid changing opacity on a native glass view or its ancestors to zero. Keep children legible above the material.

```tsx
const target = useRef<View>(null);
return <View style={{flex: 1}}>
  <BlurTargetView ref={target} style={StyleSheet.absoluteFill}>
    <Image source={localBackdrop} style={StyleSheet.absoluteFill} />
  </BlurTargetView>
  <BlurView blurTarget={target} blurMethod="dimezisBlurViewSdk31Plus"
    tint="light" intensity={55} style={{borderRadius:24, overflow:'hidden'}}>
    <Text>Collection</Text>
  </BlurView>
</View>;
```

Use the full GlassSurface wrapper for capability and accessibility checks; the example above shows the Android
blur-target relationship only. On iOS 26, glass bodies that should merge (a stepper's two halves, a toolbar group)
go inside one `GlassContainer spacing={…}` from `expo-glass-effect`. No Skia/WebGL shader port is included.
Dispersion, caustics, iridescence, morph, liquid-metal and border-beam web demos must not be advertised as native
implementations.

### Tokens

`native/src/theme.tsx` holds the colour tokens of the design language (text, secondary text, accent, danger, dim) with
the same values. Its `fill` is the frost fill, because every non-refracting branch (blur, opaque) is frost; `surface`
is the opaque fallback and the dialog panel. Use `colors.accent`, never a literal, so both themes stay in step.
Shadow tokens are CSS; on native use `shadowColor`/`shadowOpacity`/`shadowRadius` (iOS) and `elevation` (Android).

### Platform behavior and validation

Use safe-area insets for the top content and floating tab bar. Controls need at least 48 dp touch targets, labels,
accessibility roles and selected/checked/disabled state. Keep Switch and Slider behavior native. Text fields need
keyboard types and scrolling/keyboard avoidance. A React Native Modal must implement `onRequestClose` for Android
back. The shipped dialog deliberately uses an opaque surface for legibility.

Metro bundles for both targets are not enough: launch and interact on both platforms before claiming runtime
support, capture real simulator/emulator output, record OS, runtime and material branch, and annotate the renderer as
`react-native`. `get_platform_support` records what has been verified so far.

### Acceptance

- Navigation, text entry, switch, checkbox, slider, stepper bounds and dialog work by touch on both Android and iOS.
- Light and dark, safe areas, keyboard avoidance and Android back dismissal of the dialog.
- Each material branch is reached and looks right: iOS 26 glass, earlier-iOS blur, Android 31+ blur, Android < 31
  opaque, and Reduce Transparency opaque. No blur branch is described as refraction.
- The bend and fold checks of the design checklist apply to the iOS 26 glass branch only; judge the blur branches as
  frost (backdrop detail under every body, rim, legible text).
- No DOM, CSS or WebGL imports in native components; every control has a role, label and state.

## Questions

**Does liquid glass work on Android in React Native?** Not as refraction. Android API 31+ gets a blur (frost) through BlurTargetView and BlurView; nothing on Android bends the backdrop the way iOS 26 does.

**Which package draws the iOS glass?** `GlassView` from Expo's `expo-glass-effect`, on iOS 26. Use it only when both `isGlassEffectAPIAvailable()` and `isLiquidGlassAvailable()` are true, and fall back otherwise, as the material selection below does.

**Is there a starter project?** Yes: an Expo SDK 55 project with 16 components and the fallbacks wired, available to paid plans from the account page.
