Native bottom tabs (Liquid Glass)
Real Liquid Glass NativeTabs on iOS 26+, and a floating blur glass tab bar with the same scroll-collapse on iOS 18 and older, Android and web.
Installation
Run it in the root of an Expo Router app. It copies the files, creates a route for every tab and installs the dependencies.
Works on every iOS version
Real Liquid Glass only exists on iOS 26 (and the app must be built with Xcode 26). On anything older the system tab bar is the plain iOS 18 bar — so the template checks isLiquidGlassAvailable() at launch and picks the best bar for the device:
- iOS 26+
- System NativeTabs with real Liquid Glass
- Native minimize on scroll, search role, SF Symbols
- iOS 18 and older
- Floating blur glass pill (GlassTabBar)
- Same collapse-into-a-circle on scroll, sliding selection bubble
- Android
- Floating blur glass pill (or Material bar)
- Set TAB_BAR.legacy = 'native' for the system bar
- Web
- Floating glass pill
- Works in the browser and Expo Go
| Platform | Tab bar | Notes |
|---|---|---|
| iOS 26+ | System NativeTabs with real Liquid Glass | Native minimize on scroll, search role, SF Symbols |
| iOS 18 and older | Floating blur glass pill (GlassTabBar) | Same collapse-into-a-circle on scroll, sliding selection bubble |
| Android | Floating blur glass pill (or Material bar) | Set TAB_BAR.legacy = 'native' for the system bar |
| Web | Floating glass pill | Works in the browser and Expo Go |
NativeTabs.Trigger.Icon / .Label / .Badge, and SDK 56 moved navigation themes into expo-router. Run npx @expokit/cli@latest update to get the fixed files — your tabs.ts is kept.Configure your tabs
Everything lives in src/lib/tabs.ts: labels, SF Symbols for iOS, vector icons for Android and the fallback bar, badges and colours. Add a tab there and run npx @expokit/cli@latest update to create its route.
export const TAB_BAR = { minimizeBehavior: 'onScrollDown', // 'never' | 'onScrollUp' | 'automatic' legacy: 'glass', // 'native' = system tab bar below iOS 26 labelVisibilityMode: 'labeled', colors: { tint: { light: '#007AFF', dark: '#0A84FF' }, inactive: { light: 'rgba(60,60,67,0.6)', dark: 'rgba(235,235,245,0.6)' }, },}; export const TABS: TabItem[] = [ { name: 'index', title: 'Home', sf: { default: 'house', selected: 'house.fill' }, // iOS icon: { set: 'Ionicons', name: 'home-outline', selected: 'home' }, // Android, web, fallback }, { name: 'alerts', title: 'Alerts', badge: '3', sf: 'bell', icon: { set: 'Feather', name: 'bell' } },];Scroll to collapse
iOS 26 collapses the bar natively. For the glass fallback, pass useTabBarScroll() to your ScrollView — the bar shrinks into a glass circle holding the active tab, and a tap brings it back.
import { ScrollView } from 'react-native';import { useTabBarInset, useTabBarScroll } from '@/lib/tab-bar'; export default function Feed() { const onScroll = useTabBarScroll(); // collapses the glass bar on older iOS / Android / web const bottom = useTabBarInset(); // keeps the last row clear of the floating bar return ( <ScrollView onScroll={onScroll} scrollEventThrottle={16} contentContainerStyle={{ paddingBottom: bottom }}> {/* … */} </ScrollView> );}
