gorhom/react-native-animated-tabbar

A 60FPS animated tab bar with a variety of cool animation presets 😎

TypeScript

1,852

94 commits

updated Dec 27, 2022

See the code

README

Animated TabBar

npm npm npm

A 60FPS animated tab bar with a variety of cool animation presets 😎


Table of Contents

  1. Features
  2. Installation
  3. Usage
    1. Animated Icons
  4. Props
  5. Presets
    1. Bubble Preset
    2. Flashy Preset
    3. Material Preset
  6. Migration
  7. To Do
  8. Credits
  9. License

Features

  • 60FPS smooth animation for all presets.
  • Fully integrated with React Navigation v4 & v5.
  • Standalone usage.
  • Right-to-left layout support.
  • Accessibility support.
  • Written in TypeScript.

Installation

yarn add @gorhom/animated-tabbar
# or
npm install @gorhom/animated-tabbar

Also, you need to install react-native-reanimated, react-native-gesture-handler & react-native-svg, and follow their installation instructions.

Usage

Originally Animated TabBar worked only with React Navigation, but I notice that it could be use as a standalone component and be more useful for the community.

Now the library export two main components:

  • AnimatedTabBar ( default ) : the React Navigation integrated tab bar.
  • AnimatedTabBarView: the standalone tab bar.
Standalone Component
import React, { useState } from 'react';
import { View, Text, StyleSheet } from 'react-native';
import AnimatedTabBar, {TabsConfig, BubbleTabBarItemConfig} from '@gorhom/animated-tabbar';

const tabs: TabsConfig<BubbleTabBarItemConfig> = {
  Home: {
    labelStyle: {
      color: '#5B37B7',
    },
    icon: {
      component: /* ICON COMPONENT */,
      activeColor: 'rgba(91,55,183,1)',
      inactiveColor: 'rgba(0,0,0,1)',
    },
    background: {
      activeColor: 'rgba(223,215,243,1)',
      inactiveColor: 'rgba(223,215,243,0)',
    },
  },
  Profile: {
    labelStyle: {
      color: '#1194AA',
    },
    icon: {
      component: /* ICON COMPONENT */,
      activeColor: 'rgba(17,148,170,1)',
      inactiveColor: 'rgba(0,0,0,1)',
    },
    background: {
      activeColor: 'rgba(207,235,239,1)',
      inactiveColor: 'rgba(207,235,239,0)',
    },
  },
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#999',
  },
  tabBarContainer: {
    borderRadius: 25,
  },
});

export default function App() {
  const [index, setIndex] = useState(0);
  return (
    <View style={styles.container}>
      <Text>{index}</Text>
      <AnimatedTabBarView
        tabs={tabs}
        itemOuterSpace={{
          horizontal: 6,
          vertical: 12,
        }}
        itemInnerSpace={12}
        iconSize={20}
        style={styles.tabBarContainer}
        index={index}
        onIndexChange={setIndex}
      />
    </View>
  )
}
React Navigation v5 (TypeScript)
import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import AnimatedTabBar, {TabsConfig, BubbleTabBarItemConfig} from '@gorhom/animated-tabbar';

const tabs: TabsConfig<BubbleTabBarItemConfig> = {
  Home: {
    labelStyle: {
      color: '#5B37B7',
    },
    icon: {
      component: /* ICON COMPONENT */,
      activeColor: 'rgba(91,55,183,1)',
      inactiveColor: 'rgba(0,0,0,1)',
    },
    background: {
      activeColor: 'rgba(223,215,243,1)',
      inactiveColor: 'rgba(223,215,243,0)',
    },
  },
  Profile: {
    labelStyle: {
      color: '#1194AA',
    },
    icon: {
      component: /* ICON COMPONENT */,
      activeColor: 'rgba(17,148,170,1)',
      inactiveColor: 'rgba(0,0,0,1)',
    },
    background: {
      activeColor: 'rgba(207,235,239,1)',
      inactiveColor: 'rgba(207,235,239,0)',
    },
  },
};

const Tab = createBottomTabNavigator();

export default function App() {
  return (
    <NavigationContainer>
      <Tab.Navigator
        tabBar={props => (
          <AnimatedTabBar tabs={tabs} {...props} />
        )}
      >
        <Tab.Screen
          name="Home"
          component={HomeScreen}
        />
        <Tab.Screen
          name="Profile"
          component={ProfileScreen}
        />
      </Tab.Navigator>
    </NavigationContainer>
  )
}
React Navigation v5 (JavaScript)
import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import AnimatedTabBar from '@gorhom/animated-tabbar';

const tabs = {
  Home: { // < Screen name
    labelStyle: {
      color: '#5B37B7',
    },
    icon: {
      component: /* ICON COMPONENT */,
      activeColor: 'rgba(91,55,183,1)',
      inactiveColor: 'rgba(0,0,0,1)',
    },
    background: {
      activeColor: 'rgba(223,215,243,1)',
      inactiveColor: 'rgba(223,215,243,0)',
    },
  },
  Profile: { // < Screen name
    labelStyle: {
      color: '#1194AA',
    },
    icon: {
      component: /* ICON COMPONENT */,
      activeColor: 'rgba(17,148,170,1)',
      inactiveColor: 'rgba(0,0,0,1)',
    },
    background: {
      activeColor: 'rgba(207,235,239,1)',
      inactiveColor: 'rgba(207,235,239,0)',
    },
  },
};

const Tab = createBottomTabNavigator();

export default function App() {
  return (
    <NavigationContainer>
      <Tab.Navigator
        tabBar={props => (
          <AnimatedTabBar tabs={tabs} {...props} />
        )}
      >
        <Tab.Screen
          name="Home"
          component={HomeScreen}
        />
        <Tab.Screen
          name="Profile"
          component={ProfileScreen}
        />
      </Tab.Navigator>
    </NavigationContainer>
  )
}
React Navigation v4
import React from 'react';
import {createAppContainer} from 'react-navigation';
import {createBottomTabNavigator} from 'react-navigation-tabs';
import {SafeAreaProvider} from 'react-native-safe-area-context';
import AnimatedTabBar, {TabsConfig, BubbleTabBarItemConfig} from '@gorhom/animated-tabbar';

const tabs: TabsConfig<BubbleTabConfig> = {
  Home: {
    labelStyle: {
      color: '#5B37B7',
    },
    icon: {
      component: /* ICON COMPONENT */,
      activeColor: 'rgba(91,55,183,1)',
      inactiveColor: 'rgba(0,0,0,1)',
    },
    background: {
      activeColor: 'rgba(223,215,243,1)',
      inactiveColor: 'rgba(223,215,243,0)',
    },
  },
  Profile: {
    labelStyle: {
      color: '#1194AA',
    },
    icon: {
      component: /* ICON COMPONENT */,
      activeColor: 'rgba(17,148,170,1)',
      inactiveColor: 'rgba(0,0,0,1)',
    },
    background: {
      activeColor: 'rgba(207,235,239,1)',
      inactiveColor: 'rgba(207,235,239,0)',
    },
  },
};

const TabNavigator = createBottomTabNavigator(
  {
    Home: HomeScreen,
    Profile: ProfileScreen,
  },
  {
    tabBarComponent: props => <AnimatedTabBar tabs={tabs} {...props} />,
  },
);

const AppContainer = createAppContainer(TabNavigator);

export default () => (
  <SafeAreaProvider>
    <AppContainer />
  </SafeAreaProvider>
);

To configure animated icons, please have a look at Animated Icons.

Props

namedescriptionrequiredtypedefault
presetAnimation preset, currently options are ['bubble', 'flashy', 'material'].NOPresetEnum'bubble'
tabsTabs configurations. A generic dictionary of selected preset tab config.YESTabsConfig<T>
styleView style to be applied to tab bar container, default value will be based on selected preset.NOStyleProp
durationAnimation duration, default value will be based on selected preset.NOnumber
easingAnimation easing function, default value will be based on selected preset.NOEasingFunction
itemInnerSpaceTab item inner space to be added to the tab item, default value will be based on selected preset.NOnumber | Space
itemOuterSpaceTab item outer space to be added to the tab item, default value will be based on selected preset.NOnumber | Space
itemContainerWidthTab item width stretch strategy, default value will be based on selected preset.NO'auto' | 'fill'
iconSizeTab item icon size, default value will be based on selected preset.NOnumber
isRTLTab bar layout and animation direction.NObooleanfalse
onLongPressCallback on item long press, by default it is integrated with React Navigation.NO(index: number) => voidnoop

Preset Configurations

Some presets will have its own configurations - like material - which they will be added the root view props.

Material Preset Example

notice here we added animation, inactiveOpacity & inactiveScale to the root view.


import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import AnimatedTabBar, {TabsConfig, MaterialTabBarItemConfig} from '@gorhom/animated-tabbar';

const tabs: TabsConfig<MaterialTabBarItemConfig> = {
Home: {
  icon: {
    component: /* ICON COMPONENT */,
    color: 'rgba(255,255,255,1)',
  },
  ripple: {
    color: '#5B37B7',
  },
},
Profile: {
  icon: {
    component: /* ICON COMPONENT */,
    color: 'rgba(255,255,255,1)',
  },
  ripple: {
    color: '#1194AA',
  },
},
};

const Tab = createBottomTabNavigator();

export default function App() {
return (
  <NavigationContainer>
    <Tab.Navigator
      tabBar={props => (
        <AnimatedTabBar
          preset='material'
          tabs={tabs}
          animation="iconWithLabelOnFocus"
          inactiveOpacity={0.25}
          inactiveScale={0.5}
          {...props}
        />
      )}
    >
      <Tab.Screen
        name="Home"
        component={HomeScreen}
      />
      <Tab.Screen
        name="Profile"
        component={ProfileScreen}
      />
    </Tab.Navigator>
  </NavigationContainer>
)
}

Presets

Originally Animated TabBar started with Bubble as the only animation preset embedded. However, I felt the library structure could include many other variety of animation presets.

Bubble Preset

Flashy Preset

Material Preset

Migration

V1 to V2

Due to extend the library functionality, I had to rename existing interfaces as following:

  • BubbleTabConfig to BubbleTabBarItemConfig
  • BubbleTabIconProps to BubbleTabBarIconProps
  • FlashyTabConfig to FlashyTabBarItemConfig
  • FlashyTabIconProps to FlashyTabBarIconProps

Author

To keep this library maintained and up-to-date please consider sponsoring it on GitHub. Or if you are looking for a private support or help in customizing the experience, then reach out to me on Twitter @gorhom.

License

MIT

Built With ❀️


Mo Gorhom

animated
react-native
react-navigation
reanimated
ta
tabbar

gorhom/react-native-animated-tabbar

A 60FPS animated tab bar with a variety of cool animation presets 😎

TypeScript

1,852

94 commits

updated Dec 27, 2022

See the code

README

Animated TabBar

npm npm npm

A 60FPS animated tab bar with a variety of cool animation presets 😎


Table of Contents

  1. Features
  2. Installation
  3. Usage
    1. Animated Icons
  4. Props
  5. Presets
    1. Bubble Preset
    2. Flashy Preset
    3. Material Preset
  6. Migration
  7. To Do
  8. Credits
  9. License

Features

  • 60FPS smooth animation for all presets.
  • Fully integrated with React Navigation v4 & v5.
  • Standalone usage.
  • Right-to-left layout support.
  • Accessibility support.
  • Written in TypeScript.

Installation

yarn add @gorhom/animated-tabbar
# or
npm install @gorhom/animated-tabbar

Also, you need to install react-native-reanimated, react-native-gesture-handler & react-native-svg, and follow their installation instructions.

Usage

Originally Animated TabBar worked only with React Navigation, but I notice that it could be use as a standalone component and be more useful for the community.

Now the library export two main components:

  • AnimatedTabBar ( default ) : the React Navigation integrated tab bar.
  • AnimatedTabBarView: the standalone tab bar.
Standalone Component
import React, { useState } from 'react';
import { View, Text, StyleSheet } from 'react-native';
import AnimatedTabBar, {TabsConfig, BubbleTabBarItemConfig} from '@gorhom/animated-tabbar';

const tabs: TabsConfig<BubbleTabBarItemConfig> = {
  Home: {
    labelStyle: {
      color: '#5B37B7',
    },
    icon: {
      component: /* ICON COMPONENT */,
      activeColor: 'rgba(91,55,183,1)',
      inactiveColor: 'rgba(0,0,0,1)',
    },
    background: {
      activeColor: 'rgba(223,215,243,1)',
      inactiveColor: 'rgba(223,215,243,0)',
    },
  },
  Profile: {
    labelStyle: {
      color: '#1194AA',
    },
    icon: {
      component: /* ICON COMPONENT */,
      activeColor: 'rgba(17,148,170,1)',
      inactiveColor: 'rgba(0,0,0,1)',
    },
    background: {
      activeColor: 'rgba(207,235,239,1)',
      inactiveColor: 'rgba(207,235,239,0)',
    },
  },
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#999',
  },
  tabBarContainer: {
    borderRadius: 25,
  },
});

export default function App() {
  const [index, setIndex] = useState(0);
  return (
    <View style={styles.container}>
      <Text>{index}</Text>
      <AnimatedTabBarView
        tabs={tabs}
        itemOuterSpace={{
          horizontal: 6,
          vertical: 12,
        }}
        itemInnerSpace={12}
        iconSize={20}
        style={styles.tabBarContainer}
        index={index}
        onIndexChange={setIndex}
      />
    </View>
  )
}
React Navigation v5 (TypeScript)
import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import AnimatedTabBar, {TabsConfig, BubbleTabBarItemConfig} from '@gorhom/animated-tabbar';

const tabs: TabsConfig<BubbleTabBarItemConfig> = {
  Home: {
    labelStyle: {
      color: '#5B37B7',
    },
    icon: {
      component: /* ICON COMPONENT */,
      activeColor: 'rgba(91,55,183,1)',
      inactiveColor: 'rgba(0,0,0,1)',
    },
    background: {
      activeColor: 'rgba(223,215,243,1)',
      inactiveColor: 'rgba(223,215,243,0)',
    },
  },
  Profile: {
    labelStyle: {
      color: '#1194AA',
    },
    icon: {
      component: /* ICON COMPONENT */,
      activeColor: 'rgba(17,148,170,1)',
      inactiveColor: 'rgba(0,0,0,1)',
    },
    background: {
      activeColor: 'rgba(207,235,239,1)',
      inactiveColor: 'rgba(207,235,239,0)',
    },
  },
};

const Tab = createBottomTabNavigator();

export default function App() {
  return (
    <NavigationContainer>
      <Tab.Navigator
        tabBar={props => (
          <AnimatedTabBar tabs={tabs} {...props} />
        )}
      >
        <Tab.Screen
          name="Home"
          component={HomeScreen}
        />
        <Tab.Screen
          name="Profile"
          component={ProfileScreen}
        />
      </Tab.Navigator>
    </NavigationContainer>
  )
}
React Navigation v5 (JavaScript)
import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import AnimatedTabBar from '@gorhom/animated-tabbar';

const tabs = {
  Home: { // < Screen name
    labelStyle: {
      color: '#5B37B7',
    },
    icon: {
      component: /* ICON COMPONENT */,
      activeColor: 'rgba(91,55,183,1)',
      inactiveColor: 'rgba(0,0,0,1)',
    },
    background: {
      activeColor: 'rgba(223,215,243,1)',
      inactiveColor: 'rgba(223,215,243,0)',
    },
  },
  Profile: { // < Screen name
    labelStyle: {
      color: '#1194AA',
    },
    icon: {
      component: /* ICON COMPONENT */,
      activeColor: 'rgba(17,148,170,1)',
      inactiveColor: 'rgba(0,0,0,1)',
    },
    background: {
      activeColor: 'rgba(207,235,239,1)',
      inactiveColor: 'rgba(207,235,239,0)',
    },
  },
};

const Tab = createBottomTabNavigator();

export default function App() {
  return (
    <NavigationContainer>
      <Tab.Navigator
        tabBar={props => (
          <AnimatedTabBar tabs={tabs} {...props} />
        )}
      >
        <Tab.Screen
          name="Home"
          component={HomeScreen}
        />
        <Tab.Screen
          name="Profile"
          component={ProfileScreen}
        />
      </Tab.Navigator>
    </NavigationContainer>
  )
}
React Navigation v4
import React from 'react';
import {createAppContainer} from 'react-navigation';
import {createBottomTabNavigator} from 'react-navigation-tabs';
import {SafeAreaProvider} from 'react-native-safe-area-context';
import AnimatedTabBar, {TabsConfig, BubbleTabBarItemConfig} from '@gorhom/animated-tabbar';

const tabs: TabsConfig<BubbleTabConfig> = {
  Home: {
    labelStyle: {
      color: '#5B37B7',
    },
    icon: {
      component: /* ICON COMPONENT */,
      activeColor: 'rgba(91,55,183,1)',
      inactiveColor: 'rgba(0,0,0,1)',
    },
    background: {
      activeColor: 'rgba(223,215,243,1)',
      inactiveColor: 'rgba(223,215,243,0)',
    },
  },
  Profile: {
    labelStyle: {
      color: '#1194AA',
    },
    icon: {
      component: /* ICON COMPONENT */,
      activeColor: 'rgba(17,148,170,1)',
      inactiveColor: 'rgba(0,0,0,1)',
    },
    background: {
      activeColor: 'rgba(207,235,239,1)',
      inactiveColor: 'rgba(207,235,239,0)',
    },
  },
};

const TabNavigator = createBottomTabNavigator(
  {
    Home: HomeScreen,
    Profile: ProfileScreen,
  },
  {
    tabBarComponent: props => <AnimatedTabBar tabs={tabs} {...props} />,
  },
);

const AppContainer = createAppContainer(TabNavigator);

export default () => (
  <SafeAreaProvider>
    <AppContainer />
  </SafeAreaProvider>
);

To configure animated icons, please have a look at Animated Icons.

Props

namedescriptionrequiredtypedefault
presetAnimation preset, currently options are ['bubble', 'flashy', 'material'].NOPresetEnum'bubble'
tabsTabs configurations. A generic dictionary of selected preset tab config.YESTabsConfig<T>
styleView style to be applied to tab bar container, default value will be based on selected preset.NOStyleProp
durationAnimation duration, default value will be based on selected preset.NOnumber
easingAnimation easing function, default value will be based on selected preset.NOEasingFunction
itemInnerSpaceTab item inner space to be added to the tab item, default value will be based on selected preset.NOnumber | Space
itemOuterSpaceTab item outer space to be added to the tab item, default value will be based on selected preset.NOnumber | Space
itemContainerWidthTab item width stretch strategy, default value will be based on selected preset.NO'auto' | 'fill'
iconSizeTab item icon size, default value will be based on selected preset.NOnumber
isRTLTab bar layout and animation direction.NObooleanfalse
onLongPressCallback on item long press, by default it is integrated with React Navigation.NO(index: number) => voidnoop

Preset Configurations

Some presets will have its own configurations - like material - which they will be added the root view props.

Material Preset Example

notice here we added animation, inactiveOpacity & inactiveScale to the root view.


import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import AnimatedTabBar, {TabsConfig, MaterialTabBarItemConfig} from '@gorhom/animated-tabbar';

const tabs: TabsConfig<MaterialTabBarItemConfig> = {
Home: {
  icon: {
    component: /* ICON COMPONENT */,
    color: 'rgba(255,255,255,1)',
  },
  ripple: {
    color: '#5B37B7',
  },
},
Profile: {
  icon: {
    component: /* ICON COMPONENT */,
    color: 'rgba(255,255,255,1)',
  },
  ripple: {
    color: '#1194AA',
  },
},
};

const Tab = createBottomTabNavigator();

export default function App() {
return (
  <NavigationContainer>
    <Tab.Navigator
      tabBar={props => (
        <AnimatedTabBar
          preset='material'
          tabs={tabs}
          animation="iconWithLabelOnFocus"
          inactiveOpacity={0.25}
          inactiveScale={0.5}
          {...props}
        />
      )}
    >
      <Tab.Screen
        name="Home"
        component={HomeScreen}
      />
      <Tab.Screen
        name="Profile"
        component={ProfileScreen}
      />
    </Tab.Navigator>
  </NavigationContainer>
)
}

Presets

Originally Animated TabBar started with Bubble as the only animation preset embedded. However, I felt the library structure could include many other variety of animation presets.

Bubble Preset

Flashy Preset

Material Preset

Migration

V1 to V2

Due to extend the library functionality, I had to rename existing interfaces as following:

  • BubbleTabConfig to BubbleTabBarItemConfig
  • BubbleTabIconProps to BubbleTabBarIconProps
  • FlashyTabConfig to FlashyTabBarItemConfig
  • FlashyTabIconProps to FlashyTabBarIconProps

Author

To keep this library maintained and up-to-date please consider sponsoring it on GitHub. Or if you are looking for a private support or help in customizing the experience, then reach out to me on Twitter @gorhom.

License

MIT

Built With ❀️


Mo Gorhom

animated
react-native
react-navigation
reanimated
ta
tabbar

Project health

Overall

2.0/10

Maintained

0/10

Code review

1/10
OpenSSF Scorecard

Latest release

2.1.2 Β· Jun 29, 2021

Releases this year

0

Significant stargazers

Corbin Crutchley

1,117 followers Β· starred May 2025

Luca Maraschi

150 followers Β· starred Apr 2020

Toshiaki Tanaka

13 followers Β· starred Sep 2022

Leedom

23 followers Β· starred Apr 2021