Skip to content

Repository files navigation

react-native-jelly-tabs

npm version license React Native >=0.76 Reanimated 3–4 Gesture Handler 2–3 Runs with Expo Expo Router
Platforms: Android, iOS and Web

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.

Features

  • ⭐️ 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 tabLongPress events.
  • 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.

Installation

npm install react-native-jelly-tabs
Dependencies

Using Expo install

npx expo install @react-native-masked-view/masked-view react-native-gesture-handler react-native-reanimated react-native-svg

Without expo install

npm install @react-native-masked-view/masked-view react-native-gesture-handler react-native-reanimated react-native-svg

Then 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.

Compatible versions

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

Usage with Expo Router or React Navigation

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.

Router-independent component

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.

Development

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:web

Other useful commands:

bun run dev
bun run typecheck
bun run example:android
bun run example:ios

Don't be afraid to open issues or Pull Requests, especially for documentation! :)

About

A jelly-like animated tab bar for React Native, built with Reanimated, Gesture Handler and Masked View

Topics

Resources

Stars

54 stars

Watchers

0 watching

Forks

Releases

Contributors

Languages