Skip to content

Tabs

Overview

The Tabs components are a flexible navigation element for managing multiple screens or views. It supports animations, scrolling synchronization, badges, and customizable styles, making it adaptable to various UI requirements.

This library provides follow Tabs components:

  • Primary Tabs: placed at the top of the content pane under a top app bar. They display the main content destinations.

primary tabs

primary tabs with badges

  • Secondary Tabs: used within a content area to further separate related content and establish hierarchy.

secondary tabs

secondary tabs with badges

Properties

namedescriptiontypedefault
tabsRequired. Array of Tab objects.Tab[]-
activeTabState-managed active tab. Pass this prop to enable indicator animation when scrollAnim is not provided.T-
scrollAnimOptional animation progress. Range: 0 to 1 / tabs.length. For scrolling responsiveness, see the Scroll Animation Integration section.SharedValue(number)-
badgeSizeBadge size: SMALL or BIG.SMALL or BIGBIG
animConfigOptional configuration for tab animations.(routeName: T) => void-
tabIconPropsOptional properties for tab icons.Y-
tabStyleCustom styles for individual tabs. VViewStyle-
badgeStyleCustom styles for badges.ViewStyle-
indicatorStyleCustom styles for the indicator.ViewStyle-
tabsContainerStyleCustom styles for the container holding all tabs.ViewStyle-
tabInnerContentStyleCustom styles for the content within each tab.ViewStyle-
tabTitleStyleCustom styles for tab titles.TextStyle-

Tab Interface

Each Tabs component requires the tabs property, an array of Tab objects. The structure of a Tab is as follows:

typescript
export interface Tab<T, Y> extends Omit<TouchableOpacityProps, 'onPress'> {
  routeName: T;              // Unique identifier for the tab
  title?: string;            // Optional title of the tab
  icon?: React.FC<Y>;        // Optional icon component for the tab
  iconProps?: Y;             // Optional properties for the icon
  titleStyle?: TextStyle;    // Optional custom styles for the tab title
  onPress: (routeName: T) => void; // Function called when the tab is pressed
}

Scroll Animation Integration

To synchronize the tab indicator with scrolling behavior, manage the scrollAnim state in the parent component and pass it as a prop to the Tabs component.

typescript
import React from 'react';
import { Animated, useWindowDimensions, Text } from 'react-native';
import { useSharedValue, withTiming, interpolate, runOnJS } from 'react-native-reanimated';
import { Tab, SecondaryTabs } from './components';

const ParentComponent: React.FC = () => {
  const { width: windowWidth } = useWindowDimensions();
  const activeViewAnim = useSharedValue(0);
  const scrollViewRef = React.useRef<Animated.ScrollView>(null);

  const tabs: Tab[] = [
    { routeName: 'Screen1', title: 'Screen 1', onPress: () => handleScrollToScreen1() },
    { routeName: 'Screen2', title: 'Screen 2', onPress: () => handleScrollToScreen2() },
  ];

  const maxOutput = 1 / tabs.length;

  const handleScrollToScreen1 = () => {
    activeViewAnim.value = withTiming(0);
    scrollViewRef.current?.scrollTo({ x: 0 });
  };

  const handleScrollToScreen2 = () => {
    activeViewAnim.value = withTiming(maxOutput);
    scrollViewRef.current?.scrollToEnd();
  };

  const scrollHandler = useAnimatedScrollHandler({
    onScroll: (e) => {
      activeViewAnim.value = interpolate(e.contentOffset.x, [0, windowWidth], [0, maxOutput]);
    },
    onEndDrag: (e) => {
      if (e.contentOffset.x > maxOutput * windowWidth) {
        runOnJS(handleScrollToScreen2)();
      } else {
        runOnJS(handleScrollToScreen1)();
      }
    },
  });

  return (
    <>
      <SecondaryTabs scrollAnim={activeViewAnim} tabs={tabs} />
      <Animated.ScrollView
        horizontal
        ref={scrollViewRef}
        bounces={false}
        showsHorizontalScrollIndicator={false}
        onScroll={scrollHandler}
      >
        <Text style={{ width: windowWidth, paddingStart: 20 }}>Screen 1</Text>
        <Text style={{ width: windowWidth, paddingStart: 20 }}>Screen 2</Text>
      </Animated.ScrollView>
    </>
  );
};