A jelly-like animated tab bar for React Native, built with Reanimated, Gesture Handler and Masked View
tabdemofinal.mp4
Demo at: https://jelly.felipe.software/
Still under development. Supports Android, iOS and React Native Web.
- ⭐️ Runs on Android, iOS and React Native Web.
- ⭐️ Drop-in integration with Expo Router and React Navigation bottom tabs.
- ⭐️ Compatible with Expo and bare React Native projects.
- Smooth jelly snapping, dragging and press interactions powered by Reanimated and Gesture Handler.
- Navigation-aware selection that follows deep links, hardware back and programmatic navigation.
- Expo Router hidden tabs through
href: null, including hidden focused routes with no false selection. - Per-tab accessibility semantics for VoiceOver and TalkBack, including selected state and activation actions.
- Navigation badges, test IDs, accessibility labels, label styles and
tabLongPressevents. - Headless component for custom routers and fully controlled tab state.
- Custom icons, colors, opacity, sizing, springs, distortion, backdrops and touch feedback.
- Compatible with Reanimated 3–4 and Gesture Handler 2–3 within the supported React Native ranges below.
- Written in TypeScript with bundled type declarations.
npm install react-native-jelly-tabsUsing Expo install
npx expo install @react-native-masked-view/masked-view react-native-gesture-handler react-native-reanimated react-native-svgWithout expo install
npm install @react-native-masked-view/masked-view react-native-gesture-handler react-native-reanimated react-native-svgThen rebuild the native app — npx expo prebuild on Expo, or pod install + a fresh build on bare React Native. Aside from that command, Expo and bare React Native are identical here.
Reanimated & Gesture Handler setup
React Native Gesture Handler v2 needs extra steps to finalize its installation instructions.
Please make sure to wrap your App with GestureHandlerRootView when you've upgraded to React Native Gesture Handler ^2.
React Native Reanimated v3 needs extra steps to finalize its installation: installation instructions.
Jelly Tabs works across a couple of major versions of each native dependency, so you can match whatever your app already uses:
| Package | Supported range |
|---|---|
| React Native | >=0.76 |
| Gesture Handler | >=2.25 <4 (Gesture Handler 3 needs React Native >=0.82) |
| Reanimated | >=3.16 <5 |
import { MaterialIcons } from "@react-native-vector-icons/material-icons";
import { Tabs } from "expo-router";
import { JellyTabBar } from "react-native-jelly-tabs";
export default function TabLayout() {
return (
<Tabs tabBar={(props) => <JellyTabBar {...props} floating />}>
<Tabs.Screen
name="index"
options={{
title: "Home",
tabBarIcon: ({ color, size }) => (
<MaterialIcons color={color} name="home" size={size} />
),
}}
/>
<Tabs.Screen
name="settings"
options={{
title: "Settings",
tabBarIcon: ({ color, size }) => (
<MaterialIcons color={color} name="settings" size={size} />
),
}}
/>
</Tabs>
);
}JellyTabBar is compatible with the tabBar prop from Expo Router's JavaScript tabs and React Navigation's bottom tabs.
Pass floating to position the bar over the screen instead of reserving layout space. The screen will then fill behind the bar. Scrollable screens should add enough bottom content padding for their last item to remain reachable above the floating bar.
Use JellyTabBarHeadless when you want the animated component without any navigation integration:
<JellyTabBarHeadless
items={items}
selectedIndex={selectedIndex}
onTabPress={({ index }) => setSelectedIndex(index)}
/>Each item takes an activeIcon and an inactiveIcon render function.
JellyTabBarHeadless adds no safe-area inset of its own. Give it a wrapper whose height matches config.layout.trackHeight (default 64) times displayScale.
Colors, opacity, layout, jelly springs, distortion, backdrops and touch feedback are all configurable. See CUSTOMIZATION.md for every prop and config value.
The reusable package lives in src/. The Expo playground, generated background, and color laboratory live in example/.
bun install
bun run build
bun run example:webOther useful commands:
bun run dev
bun run typecheck
bun run example:android
bun run example:iosDon't be afraid to open issues or Pull Requests, especially for documentation! :)