
Security News
Open Source Maintainers Demand Ability to Block Copilot-Generated Issues and PRs
Open source maintainers are urging GitHub to let them block Copilot from submitting AI-generated issues and pull requests to their repositories.
react-native-collapsible-tab-view
Advanced tools
If you are looking for the integration with react-native-tab-view and/or react-navigation, you need to use the v2.
Collapsible Tab View for React Native, with Reanimated.
Credits
The react-native-tab-view example app was used as template for the demos.
Default | Snap | revealHeaderOnScroll | revealHeaderOnScroll + Snap |
---|---|---|---|
![]() | ![]() | ![]() | ![]() |
Open a Terminal in the project root and run:
yarn add react-native-collapsible-tab-view@next
Then, add Reanimated v2, 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
If you want to allow scrolling from the header:
If the HeaderComponent
doesn't contain touchables set pointerEvents='none'
If HeaderComponent
does contain touchables set pointerEvents='box-none'
for them to work.
Note: With this setting any child component that should not respond to touches (e.g. <Image />
) needs to have pointerEvents
set to 'none'
. Otherwise it can become the target of a touch gesture on iOS devices and thereby preventing 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 |
---|---|---|---|
HeaderComponent | ((props: TabBarProps<T>) => React.ReactElement) | null | undefined | @obsolete use renderHeader instead. This property will be removed in 5.0.0 | |
TabBarComponent | ((props: TabBarProps<T>) => React.ReactElement) | null | undefined | MaterialTabBar | @obsolete use renderTabBar instead. This property will be removed in 5.0.0 |
allowHeaderOverscroll | boolean | 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 | number | 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 | (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 horiztontal flatlist. 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. |
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 | 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 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 |
Hook to access some key styles that make the whole think work. You can use this to get the progessViewOffset and pass to the refresh control of scroll view.
const {
contentContainerStyle,
progressViewOffset,
style,
} = useCollapsibleStyle()
name | type |
---|---|
contentContainerStyle | { minHeight: number; paddingTop: number; } |
progressViewOffset | number |
style | { width: number; } |
Returns an animated value representing the current tab index, as a floating point number.
const tabIndex = useAnimatedTabIndex()
Returns the currently focused tab name.
const focusedTab = useFocusedTab()
Returns the top distance and the header height. See the animated header example in the example folder.
const { top, height } = useHeaderMeasurements()
Any additional props are passed to the pressable component.
name | type | default | description |
---|---|---|---|
activeColor | string | undefined | null | Color applied to the label when active |
inactiveColor | string | undefined | null | Color applied to the label when inactive |
inactiveOpacity | number | undefined | 0.7 | |
index | number | ||
indexDecimal | SharedValue<number> | ||
label | string | ||
labelStyle | StyleProp<AnimateStyle<TextStyle>> | Style to apply to the tab item label | |
name | T | ||
onLayout | (((event: LayoutChangeEvent) => void) & ((event: LayoutChangeEvent) => void)) | undefined | Invoked on mount and layout changes with {nativeEvent: { layout: {x, y, width, height}}}. | |
onPress | (name: T) => void | ||
pressColor | string | undefined | #DDDDDD | |
pressOpacity | number | undefined | Platform.OS === 'ios' ? 0.2 : 1 | |
scrollEnabled | boolean | undefined | ||
style | StyleProp<ViewStyle> | Either view styles or a function that receives a boolean reflecting whether the component is currently pressed and returns view styles. |
See this open issue. We use scrollTo to synchronize the unfocused tabs, it's supposed to work only with ScrollView
, but works great with FlatList
, until the RefreshControl
is added. Note that this happens only to android.
Workaround: see the Android Shared Pull To Refresh
example in the expo app. You can have a single pull to refresh for the Tabs.Container
.
When you use the stickyHeaderIndices prop on a FlatList or stickySectionHeadersEnabled on a SectionList, the sticky elements don't scroll up when the header collapses. This happens only on iOS.
See #136.
This isn't an issue, but you need to know. When using containerRef.current.setIndex(i)
, if setting to the current index, the screen will scroll to the top. You can prevent this behavior like this:
const index = pageRef.current?.getCurrentIndex()
if (index !== nextIndex) {
pageRef.current?.setIndex(nextIndex)
}
If you don't need a full-featured tab view, check out the other option, a simple segmented control / material tab bar without swiping or snapping, using just the react native Animated API.
While developing, you can run the example app to test your changes.
Please follow the angular commit message format.
Make sure your code passes TypeScript and ESLint. Run the following to verify:
yarn typescript
yarn lint
To fix formatting errors, run the following:
yarn lint -- --fix
Remember to add tests for your change if possible.
Edit the README_TEMPLATE, or update the docstrings inside the src
folder, and run:
yarn docs
FAQs
Collapsible tab view component for React Native
The npm package react-native-collapsible-tab-view receives a total of 21,197 weekly downloads. As such, react-native-collapsible-tab-view popularity was classified as popular.
We found that react-native-collapsible-tab-view demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 2 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Open source maintainers are urging GitHub to let them block Copilot from submitting AI-generated issues and pull requests to their repositories.
Research
Security News
Malicious Koishi plugin silently exfiltrates messages with hex strings to a hardcoded QQ account, exposing secrets in chatbots across platforms.
Research
Security News
Malicious PyPI checkers validate stolen emails against TikTok and Instagram APIs, enabling targeted account attacks and dark web credential sales.