Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/felipe-software/react-native-jelly-tabs/llms.txt

Use this file to discover all available pages before exploring further.

JellyTabBar is the React Navigation–compatible adapter around JellyTabBarHeadless. Pass it to the tabBar prop of a Tabs navigator and the navigator automatically injects state, descriptors, navigation, and insets. Every other prop is yours to configure.

Import

import { JellyTabBar } from 'react-native-jelly-tabs'

Usage

Pass JellyTabBar to the tabBar prop of a React Navigation or Expo Router Tabs navigator. The navigator automatically injects state, descriptors, navigation, and insets — do not pass those props manually.
import { Tabs } from 'expo-router'
import { JellyTabBar } from 'react-native-jelly-tabs'

export default function Layout() {
  return (
    <Tabs
      tabBar={(props) => (
        <JellyTabBar
          {...props}
          floating
          maxWidth={480}
          colors={{
            surface: '#1a1a1a',
            selectedSurface: '#ffffff',
            activeContent: '#000000',
            inactiveContent: '#888888',
          }}
        />
      )}
    />
  )
}
These four props are supplied automatically by the navigator. Do not pass them yourself.
state
JellyNavigationState
required
The navigator’s current route state, including the active route index and the full route list. Supplied by React Navigation / Expo Router.
descriptors
Readonly<Record<string, JellyNavigationDescriptor>>
required
A map of route key → descriptor, each containing a options object with all screen-level navigation options. Supplied by React Navigation / Expo Router.
navigation
JellyNavigationHelpers
required
The navigator helper used to dispatch NAVIGATE actions and emit tabPress / tabLongPress events. Supplied by React Navigation / Expo Router.
insets
{ top: number; bottom: number; left: number; right: number }
required
Safe-area insets applied as padding around the tab bar container. Supplied by React Navigation / Expo Router.

Visual & layout props

floating
boolean
default:"false"
When true, the tab bar is absolutely positioned at the bottom of the screen (position: 'absolute', bottom: 0, zIndex: 1), floating above the screen content instead of occupying space in the layout.
containerStyle
StyleProp<ViewStyle>
Additional styles applied to the outermost wrapper View that holds the bar and manages safe-area padding. Use this for overrides such as a custom background color or extra padding.
maxWidth
DimensionValue
default:400
Maximum width of the tab bar track. The bar stays horizontally centered inside wider parents. Accepts any React Native DimensionValue (number, percentage string, etc.).
backdrop
ReactNode
A React node rendered below the track’s solid color layer — typically a blur view. When omitted, the tabBarBackground navigation option from the focused screen is used as a fallback.
colors
Partial<TabBarColors>
Solid color overrides for the four visual layers. Partial objects are merged over the built-in defaults. Navigation tint options (tabBarActiveTintColor, tabBarInactiveTintColor, tabBarActiveBackgroundColor, tabBarInactiveBackgroundColor) are used as a secondary fallback when a key is not present in this prop.
interface TabBarColors {
  surface: string;          // track background  — default: '#22211f'
  selectedSurface: string;  // selected pill      — default: '#f2eee7'
  activeContent: string;    // active icon/label  — default: '#11100f'
  inactiveContent: string;  // inactive icon/label — default: '#b8b4ad'
}
config
DeepPartial<TabBarConfig>
Deep-partial override of the tab bar’s layout, jelly animation, and distortion parameters. Only the keys you provide are changed; everything else falls back to the built-in defaults. See the Config shape below.
displayScale
number
default:1
Multiplier applied to every layout dimension (trackHeight, itemHeight, iconSize, etc.). Useful for recording clean thumbnails or adjusting the component to match a non-standard scale factor.
opacity
Partial<TabBarOpacity>
Per-layer opacity overrides, each clamped to [0, 1]. Opacity is applied to the rendered content rather than the mask shape, so the animated pill retains a fully opaque clip boundary.
interface TabBarOpacity {
  surface: number;          // default: 1
  selectedSurface: number;  // default: 1
  activeContent: number;    // default: 1
  inactiveContent: number;  // default: 1
}
selectedBackdrop
ReactNode
A React node rendered below the selected-pill color layer. Useful for placing a blur effect or custom background exclusively inside the active pill.
touchFeedbackEnabled
boolean
default:true
Enables or disables the radial glow that appears under the user’s finger when they interact with the bar. Set to false to remove the effect entirely.
touchFeedbackColor
string
Overrides the color of the radial touch feedback. Defaults to colors.selectedSurface when not set.
touchFeedbackOpacity
number
Overrides the base opacity of the radial touch feedback. Defaults to config.distortion.touchFeedback.opacity (0.15).
touchFeedbackScale
number
Overrides the radius scale multiplier of the radial touch feedback. Defaults to config.distortion.touchFeedback.scale (2).
recording
boolean
default:false
Enables deterministic rendering mode, which disables non-deterministic animation behaviors. Use this when capturing clean screen recordings or automated visual snapshots.
JellyTabBar reads the following standard React Navigation options from each route’s descriptor. Set them in the screenOptions or per-screen options prop of your navigator.
OptionTypeDescription
tabBarIcon(props: { color: string; focused: boolean; size: number }) => ReactNodeIcon renderer. The component is wrapped internally to produce separate active/inactive icon instances.
tabBarLabelunknownString label shown below the icon. When a string, it is displayed as the tab label; non-string values fall back to title or the route name. Function-valued tabBarLabel is not rendered by the Jelly layout.
tabBarShowLabelbooleanSet to false to hide the label (renders an empty string).
tabBarLabelStyleStyleProp<TextStyle>Style applied to the tab label text.
tabBarBadgenumber | stringBadge value displayed on the tab.
tabBarBadgeStyleStyleProp<TextStyle>Style applied to the badge.
tabBarAccessibilityLabelstringAccessibility label for the tab. Defaults to label when omitted.
tabBarButtonTestIDstringtestID for the accessible tab element.
tabBarActiveTintColorunknownActive icon/label color (string values only). Overridden by colors.activeContent when set.
tabBarInactiveTintColorunknownInactive icon/label color (string values only). Overridden by colors.inactiveContent when set.
tabBarActiveBackgroundColorunknownSelected pill color (string values only). Overridden by colors.selectedSurface when set.
tabBarInactiveBackgroundColorunknownTrack background color (string values only). Overridden by colors.surface when set.
tabBarBackground() => ReactNodeCalled to produce the backdrop node when the backdrop prop is not provided.
tabBarStyleunknownStyle merged into the container View of the focused screen’s tab bar.
titlestringFallback label when tabBarLabel is not set.
hrefunknownSet to null to hide a route from the tab bar entirely (Expo Router convention).
Function-valued tabBarLabel and custom tab button components (e.g. tabBarButton) are not rendered by the Jelly layout. Use string labels and the tabBarIcon option instead.

Config shape

config accepts a deep-partial of the following structure. Omitted keys fall back to built-in defaults.
interface TabBarConfig {
  layout: {
    iconSize: number;       // default: 28
    itemHeight: number;     // default: 56
    trackHeight: number;    // default: 64
    trackInset: number;     // default: 4
    maskOverscanX: number;  // default: 48
    maskOverscanY: number;  // default: 16
  };
  pillJelly: {
    pressedScale: number;         // default: 1.3
    snapOnPointerDown: boolean;   // default: true
    frameConfig: {
      releaseDistanceFraction: number; // default: 0.025
      springs: {
        panel:    { stiffness: number; dampingRatio: number }; // 300 / 1
        press:    { stiffness: number; dampingRatio: number }; // 1000 / 1
        scaleX:   { stiffness: number; dampingRatio: number }; // 250 / 0.6
        scaleY:   { stiffness: number; dampingRatio: number }; // 250 / 0.7
        value:    { stiffness: number; dampingRatio: number }; // 1000 / 1
        velocity: { stiffness: number; dampingRatio: number }; // 300 / 0.5
      };
    };
  };
  distortion: {
    pressedScale: number;  // default: 1.025
    touchFeedback: {
      opacity: number;              // default: 0.15
      middleOpacityRatio: number;   // default: 0.43
      radius: number;               // default: 150
      scale: number;                // default: 2
    };
    spring: { damping: number; mass: number; stiffness: number }; // 18 / 0.9 / 240
    verticalDrag: {
      distortion: number;               // default: 0.08
      distanceForMaxDistortion: number; // default: 700
      follow: number;                   // default: 0.25
      rubberBand: number;               // default: 0.14
    };
  };
}

Full example

import { Tabs } from 'expo-router'
import { BlurView } from 'expo-blur'
import { JellyTabBar } from 'react-native-jelly-tabs'
import HomeIcon from './icons/HomeIcon'
import SearchIcon from './icons/SearchIcon'
import ProfileIcon from './icons/ProfileIcon'

export default function RootLayout() {
  return (
    <Tabs
      screenOptions={{ headerShown: false }}
      tabBar={(props) => (
        <JellyTabBar
          {...props}
          floating
          maxWidth={420}
          backdrop={<BlurView intensity={60} style={{ flex: 1 }} />}
          colors={{
            surface: '#18181b',
            selectedSurface: '#fafafa',
            activeContent: '#18181b',
            inactiveContent: '#71717a',
          }}
          config={{
            pillJelly: {
              pressedScale: 1.2,
            },
          }}
        />
      )}
    >
      <Tabs.Screen
        name="index"
        options={{
          title: 'Home',
          tabBarIcon: ({ color, size }) => (
            <HomeIcon color={color} size={size} />
          ),
        }}
      />
      <Tabs.Screen
        name="search"
        options={{
          title: 'Search',
          tabBarIcon: ({ color, size }) => (
            <SearchIcon color={color} size={size} />
          ),
        }}
      />
      <Tabs.Screen
        name="profile"
        options={{
          title: 'Profile',
          tabBarIcon: ({ color, size }) => (
            <ProfileIcon color={color} size={size} />
          ),
        }}
      />
    </Tabs>
  )
}

Build docs developers (and LLMs) love