Loading repository data…
Loading repository data…
PedroBern / repository
A cross-platform Collapsible Tab View component for React Native
[![Build Status][build-badge]][build] [![Version][version-badge]][package] [![MIT License][license-badge]][license] [![Runs with Expo][expo-badge]][expo]
React Native Collapsible Tab View is a versatile library for creating collapsible tab views using Reanimated.
Credits
The react-native-tab-view example app was used as a template for the demos.
| Default | Snap | revealHeaderOnScroll | revealHeaderOnScroll + Snap |
|---|---|---|---|
To install the library, open a terminal in your project's root directory and run:
yarn add react-native-collapsible-tab-view react-native-pager-view
Then, add Reanimated, follow the official installation guide.
import React from 'react'
import { View, StyleSheet, ListRenderItem } from 'react-native'
import { Tabs } from 'react-native-collapsible-tab-view'
const HEADER_HEIGHT = 250
const DATA = [0, 1, 2, 3, 4]
const identity = (v: unknown): string => v + ''
const Header = () => {
return <View style={styles.header} />
}
const Example: React.FC = () => {
const renderItem: ListRenderItem<number> = React.useCallback(({ index }) => {
return (
<View style={[styles.box, index % 2 === 0 ? styles.boxB : styles.boxA]} />
)
}, [])
return (
<Tabs.Container
renderHeader={Header}
headerHeight={HEADER_HEIGHT} // optional
>
<Tabs.Tab name="A">
<Tabs.FlatList
data={DATA}
renderItem={renderItem}
keyExtractor={identity}
/>
</Tabs.Tab>
<Tabs.Tab name="B">
<Tabs.ScrollView>
<View style={[styles.box, styles.boxA]} />
<View style={[styles.box, styles.boxB]} />
</Tabs.ScrollView>
</Tabs.Tab>
</Tabs.Container>
)
}
const styles = StyleSheet.create({
box: {
height: 250,
width: '100%',
},
boxA: {
backgroundColor: 'white',
},
boxB: {
backgroundColor: '#D8D8D8',
},
header: {
height: HEADER_HEIGHT,
width: '100%',
backgroundColor: '#2196f3',
},
})
export default Example
To enable scrolling from the header, follow these steps:
HeaderComponent does not contain touchable components, set the pointerEvents prop to 'none'.HeaderComponent does contain touchable components, set the pointerEvents prop to 'box-none' to ensure they function properly.Note: If any child component within the HeaderComponent should not respond to touches, such as an <Image /> element, set its pointerEvents prop to 'none'. Otherwise, it may unintentionally become the target of a touch gesture on iOS devices and prevent scrolling.
Basic usage looks like this:
import { Tabs } from 'react-native-collapsible-tab-view'
const Example = () => {
return (
<Tabs.Container renderHeader={MyHeader}>
<Tabs.Tab name="A">
<ScreenA />
</Tabs.Tab>
<Tabs.Tab name="B">
<ScreenB />
</Tabs.Tab>
</Tabs.Container>
)
}
| name | type | default | description |
|---|---|---|---|
allowHeaderOverscroll | boolean | undefined | false | Whether the header moves down during overscrolling (for example on pull-to-refresh on iOS) or sticks to the top |
cancelLazyFadeIn | boolean | undefined | ||
cancelTranslation | boolean | undefined | ||
containerStyle | StyleProp<ViewStyle> | ||
headerContainerStyle | StyleProp<AnimateStyle<ViewStyle>> | ||
headerHeight | number | undefined | Is optional, but will optimize the first render. | |
initialTabName | string | undefined | ||
lazy | boolean | undefined | If lazy, will mount the screens only when the tab is visited. There is a default fade in transition. | |
minHeaderHeight | number | undefined | Header minimum height when collapsed | |
onIndexChange | ((index: number) => void) | undefined | Callback fired when the index changes. It receives the current index. | |
onTabChange |
Wrap your screens with Tabs.Tab. Basic usage looks like this:
<Tabs.Container ...>
<Tabs.Tab name="A" label="First Tab">
<ScreenA />
</Tabs.Tab>
<Tabs.Tab name="B">
<ScreenA />
</Tabs.Tab>
</Tabs.Container>
| name | type |
|---|---|
label | string | ((props: TabItemProps<T>) => ReactNode) | undefined |
name | T |
Typically used internally, but if you want to mix lazy and regular screens you can wrap the lazy ones with this component.
| name | type |
|---|---|
cancelLazyFadeIn | boolean | undefined |
startMounted | boolean | undefined |
Use like a regular FlatList.
Use like a regular FlashList.
Use like a regular MasonryFlashList.
Use like a regular ScrollView.
Use like a regular SectionList.
You can pass a ref to Tabs.Container.
const ref = React.useRef()
<Tabs.Container ref={ref}>
| method | type |
|---|---|
| jumpToTab | (name: T) => boolean |
| setIndex | (index: number) => boolean |
| getFocusedTab | () => T |
| getCurrentIndex | () => number |
useCollapsibleStyleThis hook provides access to key styles for the collapsible tab view. It can be used to obtain the progressViewOffset and pass it to the RefreshControl of the scroll view.
const {
contentContainerStyle,
progressViewOffset,
style,
} = useCollapsibleStyle()
| name | type |
|---|---|
| contentContainerStyle | { minHeight: number; paddingTop: number; } |
| progressViewOffset | number |
| style | { width: number; } |
useAnimatedTabIndexThis hook returns an animated value representing the current tab index. As the tab view can be in between panes while swiping, this value is a floating-point number.
const tabIndex = useAnimatedTabIndex()
useFocusedTabThis hook returns the name of the currently focused tab.
const focusedTab = useFocusedTab()
useHeaderMeasurementsThis hook returns the top distance and the header height. For an example of how to use this, check out the animated header example in the example folder.
const { top, height } = useHeaderMeasurements()
This hook returns the vertical scroll position of the current tab as an Animated SharedValue.
Since this library requires handling the onScroll event for its functionality, this is the only way to react to changes in the scroll position of the underlying scrollable component.
const scrollY = useCurrentTabScrollY()
Any additional props are passed to the pressable component.
| name | type | description |
|---|---|---|
activeColor | string | undefined | Color applied to the label when active |
inactiveColor | string | undefined | Color applied to the label when inactive |
inactiveOpacity | number | undefined | |
index |
(data: { prevIndex: number index: number prevTabName: T tabName: T }) => void |
| Callback fired when the tab changes. It receives the previous and current index and tabnames. |
pagerProps | Omit<FlatListProps<number>, 'data' | 'keyExtractor' | 'renderItem' | 'horizontal' | 'pagingEnabled' | 'onScroll' | 'showsHorizontalScrollIndicator' | 'getItemLayout'> | Props passed to the pager. If you want for example to disable swiping, you can pass { scrollEnabled: false } |
renderHeader | (props: TabBarProps<TabName>) => React.ReactElement | null |
renderTabBar | (props: TabBarProps<TabName>) => React.ReactElement | null | (props: TabBarProps<TabName>) => MaterialTabBar |
revealHeaderOnScroll | boolean | undefined | Reveal header when scrolling down. Implements diffClamp. |
snapThreshold | number | null | undefined | null | Percentage of header height to define as the snap point. A number between 0 and 1, or null to disable snapping. |
tabBarHeight | number | undefined | Is optional, but will optimize the first render. |
width | number | undefined | Custom width of the container. Defaults to the window width. |