Skip to main content

BottomNavigation

BottomNavigation provides quick navigation between top-level views of an app with a bottom navigation bar. It is primarily designed for use on mobile. If you want to use the navigation bar only see BottomNavigation.Bar.

By default BottomNavigation uses primary color as a background, in dark theme with adaptive mode it will use surface colour instead. See Dark Theme for more information.

Usage

import * as React from 'react';
import { BottomNavigation, Text } from 'react-native-paper';

const MusicRoute = () => <Text>Music</Text>;

const AlbumsRoute = () => <Text>Albums</Text>;

const RecentsRoute = () => <Text>Recents</Text>;

const NotificationsRoute = () => <Text>Notifications</Text>;

const MyComponent = () => {
const [index, setIndex] = React.useState(0);
const [routes] = React.useState([
{ key: 'music', title: 'Favorites', focusedIcon: 'heart', unfocusedIcon: 'heart-outline'},
{ key: 'albums', title: 'Albums', focusedIcon: 'album' },
{ key: 'recents', title: 'Recents', focusedIcon: 'history' },
{ key: 'notifications', title: 'Notifications', focusedIcon: 'bell', unfocusedIcon: 'bell-outline' },
]);

const renderScene = BottomNavigation.SceneMap({
music: MusicRoute,
albums: AlbumsRoute,
recents: RecentsRoute,
notifications: NotificationsRoute,
});

return (
<BottomNavigation
navigationState={{ index, routes }}
onIndexChange={setIndex}
renderScene={renderScene}
/>
);
};

export default MyComponent;

Props

shifting

Type: boolean

Whether the shifting style is used, the active tab icon shifts up to show the label and the inactive tabs won't have a label.

By default, this is false with theme version 3 and true when you have more than 3 tabs. Pass shifting={false} to explicitly disable this animation, or shifting={true} to always use this animation. Note that you need at least 2 tabs be able to run this animation.

labeled

Type: boolean

Default value: true

Whether to show labels in tabs. When false, only icons will be displayed.

compact

Type: boolean

Whether tabs should be spread across the entire width.

Type: { index: number; routes: Route[]; }

State for the bottom navigation. The state should contain the following properties:

  • index: a number representing the index of the active route in the routes array
  • routes: an array containing a list of route objects used for rendering the tabs

Each route object should contain the following properties:

  • key: a unique key to identify the route (required)
  • title: title of the route to use as the tab label
  • focusedIcon: icon to use as the focused tab icon, can be a string, an image source or a react component Renamed from 'icon' to 'focusedIcon' in v5.x
  • unfocusedIcon: icon to use as the unfocused tab icon, can be a string, an image source or a react component Available in v5.x with theme version 3
  • color: color to use as background color for shifting bottom navigation In v5.x works only with theme version 2.
  • badge: badge to show on the tab icon, can be true to show a dot, string or number to show text.
  • accessibilityLabel: accessibility label for the tab button
  • testID: test id for the tab button

Example:

{
  index: 1,
  routes: [
    { key: 'music', title: 'Favorites', focusedIcon: 'heart', unfocusedIcon: 'heart-outline'},
    { key: 'albums', title: 'Albums', focusedIcon: 'album' },
    { key: 'recents', title: 'Recents', focusedIcon: 'history' },
    { key: 'notifications', title: 'Notifications', focusedIcon: 'bell', unfocusedIcon: 'bell-outline' },
  ]
}

BottomNavigation is a controlled component, which means the index needs to be updated via the onIndexChange callback.

onIndexChange (required)

Type: (index: number) => void

Callback which is called on tab change, receives the index of the new tab as argument. The navigation state needs to be updated when it's called, otherwise the change is dropped.

renderScene (required)

Type: (props: { route: Route; jumpTo: (key: string) => void; }) => React.ReactNode | null

Callback which returns a react element to render as the page for the tab. Receives an object containing the route as the argument:

renderScene = ({ route, jumpTo }) => {
  switch (route.key) {
    case 'music':
      return <MusicRoute jumpTo={jumpTo} />;
    case 'albums':
      return <AlbumsRoute jumpTo={jumpTo} />;
  }
}

Pages are lazily rendered, which means that a page will be rendered the first time you navigate to it. After initial render, all the pages stay rendered to preserve their state.

You need to make sure that your individual routes implement a shouldComponentUpdate to improve the performance. To make it easier to specify the components, you can use the SceneMap helper:

renderScene = BottomNavigation.SceneMap({
  music: MusicRoute,
  albums: AlbumsRoute,
});

Specifying the components this way is easier and takes care of implementing a shouldComponentUpdate method. Each component will receive the current route and a jumpTo method as it's props. The jumpTo method can be used to navigate to other tabs programmatically:

this.props.jumpTo('albums')

renderIcon

Type: (props: { route: Route; focused: boolean; color: string; }) => React.ReactNode

Callback which returns a React Element to be used as tab icon.

renderLabel

Type: (props: { route: Route; focused: boolean; color: string; }) => React.ReactNode

Callback which React Element to be used as tab label.

renderTouchable

Type: (props: TouchableProps<Route>) => React.ReactNode

Callback which returns a React element to be used as the touchable for the tab item. Renders a TouchableRipple on Android and Pressable on iOS.

getAccessibilityLabel

Type: (props: { route: Route }) => string | undefined

Get accessibility label for the tab button. This is read by the screen reader when the user taps the tab. Uses route.accessibilityLabel by default.

getBadge

Type: (props: { route: Route }) => boolean | number | string | undefined

Get badge for the tab, uses route.badge by default.

getColor

Type: (props: { route: Route }) => string | undefined

Get color for the tab, uses route.color by default.

getLabelText

Type: (props: { route: Route }) => string | undefined

Get label text for the tab, uses route.title by default. Use renderLabel to replace label component.

getLazy

Type: (props: { route: Route }) => boolean | undefined

Default value: ({ route }: { route: Route }) => route.lazy

Get lazy for the current screen. Uses true by default.

getTestID

Type: (props: { route: Route }) => string | undefined

Get the id to locate this tab button in tests, uses route.testID by default.

onTabPress

Type: (props: { route: Route } & TabPressEvent) => void

Function to execute on tab press. It receives the route for the pressed tab, useful for things like scroll to top.

onTabLongPress

Type: (props: { route: Route } & TabPressEvent) => void

Function to execute on tab long press. It receives the route for the pressed tab, useful for things like custom action when longed pressed.

activeColor

Type: string

Custom color for icon and label in the active tab.

inactiveColor

Type: string

Custom color for icon and label in the inactive tab.

sceneAnimationEnabled

Type: boolean

Default value: false

Whether animation is enabled for scenes transitions in shifting mode. By default, the scenes cross-fade during tab change when shifting is enabled. Specify sceneAnimationEnabled as false to disable the animation.

sceneAnimationType

Type: 'opacity' | 'shifting'

Default value: 'opacity'

The scene animation effect. Specify 'shifting' for a different effect. By default, 'opacity' will be used.

sceneAnimationEasing

Type: EasingFunction | undefined

The scene animation Easing.

keyboardHidesNavigationBar

Type: boolean

Default value: Platform.OS === 'android'

Whether the bottom navigation bar is hidden when keyboard is shown. On Android, this works best when windowSoftInputMode is set to adjustResize.

safeAreaInsets

Type: { top?: number; right?: number; bottom?: number; left?: number; }

Safe area insets for the tab bar. This can be used to avoid elements like the navigation bar on Android and bottom safe area on iOS. The bottom insets for iOS is added by default. You can override the behavior with this option.

barStyle

Type: Animated.WithAnimatedValue<StyleProp<ViewStyle>>

Style for the bottom navigation bar. You can pass a custom background color here:

barStyle={{ backgroundColor: '#694fad' }}

labelMaxFontSizeMultiplier

Type: number

Default value: 1

Specifies the largest possible scale a label font can reach.

style

activeIndicatorStyle

theme

Type: ThemeProp

testID

Type: string

Default value: 'bottom-navigation'

TestID used for testing purposes