Skip to main content
Version: 7.x

Material Top Tabs Navigator

A material-design themed tab bar on the top of the screen that lets you switch between different routes by tapping the tabs or swiping horizontally. Transitions are animated by default. Screen components for each route are mounted immediately.

This wraps react-native-tab-view. If you want to use the tab view without React Navigation integration, use the library directly instead.


To use this navigator, ensure that you have @react-navigation/native and its dependencies (follow this guide), then install @react-navigation/material-top-tabs:

npm install @react-navigation/material-top-tabs@next

Then, you need to install react-native-pager-view which is required by the navigator.

If you have a Expo managed project, in your project directory, run:

npx expo install react-native-pager-view

If you have a bare React Native project, in your project directory, run:

npm install react-native-pager-view

If you're on a Mac and developing for iOS, you also need to install the pods (via Cocoapods) to complete the linking.

npx pod-install ios


To use this navigator, import it from @react-navigation/material-top-tabs:

import { createMaterialTopTabNavigator } from '@react-navigation/material-top-tabs';

const MyTabs = createMaterialTopTabNavigator({
screens: {
Home: HomeScreen,
Profile: ProfileScreen,
Try on Snack

API Definition


In addition to the common props shared by all navigators, the material top tabs navigator component accepts the following additional props:


This controls what happens when goBack is called in the navigator. This includes pressing the device's back button or back gesture on Android.

It supports the following values:

  • firstRoute - return to the first screen defined in the navigator (default)
  • initialRoute - return to initial screen passed in initialRouteName prop, if not passed, defaults to the first screen
  • order - return to screen defined before the focused screen
  • history - return to last visited screen in the navigator; if the same screen is visited multiple times, the older entries are dropped from the history
  • none - do not handle back button


Position of the tab bar in the tab view. Possible values are 'top' and 'bottom'. Defaults to 'top'.


String indicating whether the keyboard gets dismissed in response to a drag gesture. Possible values are:

  • 'auto' (default): the keyboard is dismissed when the index changes.
  • 'on-drag': the keyboard is dismissed when a drag begins.
  • 'none': drags do not dismiss the keyboard.


Object containing the initial height and width of the screens. Passing this will improve the initial rendering performance. For most apps, this is a good default:

width: Dimensions.get('window').width;


Style to apply to the view wrapping each screen. You can pass this to override some default styles such as overflow clipping.


Style to apply to the tab view container.


Function that returns a React element to display as the tab bar.


import { Animated, View, TouchableOpacity, Platform } from 'react-native';
import { useLinkBuilder, useTheme } from '@react-navigation/native';

function MyTabBar({ state, descriptors, navigation, position }) {
const { colors } = useTheme();
const { buildHref } = useLinkBuilder();

return (
<View style={{ flexDirection: 'row' }}>
{, index) => {
const { options } = descriptors[route.key];
const label =
options.tabBarLabel !== undefined
? options.tabBarLabel
: options.title !== undefined
? options.title

const isFocused = state.index === index;

const onPress = () => {
const event = navigation.emit({
type: 'tabPress',
target: route.key,
canPreventDefault: true,

if (!isFocused && !event.defaultPrevented) {
navigation.navigate(, route.params);

const onLongPress = () => {
type: 'tabLongPress',
target: route.key,

const inputRange =, i) => i);
const opacity = position.interpolate({
outputRange: => (i === index ? 1 : 0)),

return (
href={buildHref(, route.params)}
accessibilityRole={Platform.OS === 'web' ? 'link' : 'button'}
accessibilityState={isFocused ? { selected: true } : {}}
style={{ flex: 1 }}
<Animated.Text style={{ opacity, color: colors.text }}>

// ...

<Tab.Navigator tabBar={(props) => <MyTabBar {...props} />}>
{/* ... */}

This example will render a basic tab bar with labels.

Note that you cannot use the useNavigation hook inside the tabBar since useNavigation is only available inside screens. You get a navigation prop for your tabBar which you can use instead:

function MyTabBar({ navigation }) {
return (
title="Go somewhere"
onPress={() => {
// Navigate using the `navigation` prop that you received


The following options can be used to configure the screens in the navigator:


tabBarLabelStyle: { fontSize: 12 },
tabBarItemStyle: { width: 100 },
tabBarStyle: { backgroundColor: 'powderblue' },
{/* ... */}


Generic title that can be used as a fallback for headerTitle and tabBarLabel.


Title string of a tab displayed in the tab bar or a function that given { focused: boolean, color: string } returns a React.Node, to display in tab bar. When undefined, scene title is used. To hide, see tabBarShowLabel option.


Accessibility label for the tab button. This is read by the screen reader when the user taps the tab. It's recommended to set this if you don't have a label for the tab.


Whether label font should scale to respect Text Size accessibility settings.


Whether the tab label should be visible. Defaults to true.


Function that given { focused: boolean, color: string } returns a React.Node, to display in the tab bar.


Whether the tab icon should be visible. Defaults to false.


Function that returns a React element to use as a badge for the tab.


Function that returns a React element as the tab bar indicator.


Style object for the tab bar indicator.


Style object for the view containing the tab bar indicator.


ID to locate this tab button in tests.


Color for the icon and label in the active tab.


Color for the icon and label in the inactive tabs.


Color for material ripple (Android >= 5.0 only).


Opacity for pressed tab (iOS and Android < 5.0 only).


Boolean indicating whether the tab bar bounces when overscrolling.


Boolean indicating whether to make the tab bar scrollable.

If you set this to true, you should also specify a width in tabBarItemStyle to improve the performance of initial render.


Style object for the tab icon container.


Style object for the tab label.


Style object for the individual tab items.


Style object for the view containing the tab items.


Style object for the tab bar.


Boolean indicating whether to enable swipe gestures. Swipe gestures are enabled by default. Passing false will disable swipe gestures, but the user can still switch tabs by pressing the tab bar.


Whether this screen should be lazily rendered. When this is set to true, the screen will be rendered as it comes into the viewport. By default all screens are rendered to provide a smoother swipe experience. But you might want to defer the rendering of screens out of the viewport until the user sees them. To enable lazy rendering for this screen, set lazy to true.

When you enable lazy, the lazy loaded screens will usually take some time to render when they come into the viewport. You can use the lazyPlaceholder prop to customize what the user sees during this short period.


When lazy is enabled, you can specify how many adjacent screens should be preloaded in advance with this prop. This value defaults to 0 which means lazy pages are loaded as they come into the viewport.


Function that returns a React element to render if this screen hasn't been rendered yet. The lazy option also needs to be enabled for this to work.

This view is usually only shown for a split second. Keep it lightweight.

By default, this renders null.


The navigator can emit events on certain actions. Supported events are:


This event is fired when the user presses the tab button for the current screen in the tab bar. By default a tab press does several things:

  • If the tab is not focused, tab press will focus that tab
  • If the tab is already focused:
    • If the screen for the tab renders a scroll view, you can use useScrollToTop to scroll it to top
    • If the screen for the tab renders a stack navigator, a popToTop action is performed on the stack

To prevent the default behavior, you can call event.preventDefault:

React.useEffect(() => {
const unsubscribe = navigation.addListener('tabPress', (e) => {
// Prevent default behavior

// Do something manually
// ...

return unsubscribe;
}, [navigation]);


This event is fired when the user presses the tab button for the current screen in the tab bar for an extended period.


React.useEffect(() => {
const unsubscribe = navigation.addListener('tabLongPress', (e) => {
// Do something

return unsubscribe;
}, [navigation]);


The tab navigator adds the following methods to the navigation object:


Navigates to an existing screen in the tab navigator. The method accepts following arguments:

  • name - string - Name of the route to jump to.
  • params - object - Screen params to pass to the destination route.
navigation.jumpTo('Profile', { name: 'Michaś' });


The material top tab navigator exports the following hooks:


This hook returns an object containing an animated value that represents the current position of the tabs. This can be used to animate elements based on the swipe position of the tabs, such as the tab indicator:

import { Animated } from 'react-native';
import { useTabAnimation } from '@react-navigation/material-top-tabs';

function MyView() {
const { position } = useTabAnimation();

return (
width: '50%',
height: 2,
backgroundColor: 'tomato',
transform: [{ translateX: position }],