{"id":17004300,"url":"https://github.com/pedrobern/react-native-collapsible-tab-view","last_synced_at":"2025-05-13T23:07:12.522Z","repository":{"id":37713116,"uuid":"314232123","full_name":"PedroBern/react-native-collapsible-tab-view","owner":"PedroBern","description":"A cross-platform Collapsible Tab View component for React Native","archived":false,"fork":false,"pushed_at":"2025-03-29T18:44:43.000Z","size":84953,"stargazers_count":943,"open_issues_count":184,"forks_count":196,"subscribers_count":11,"default_branch":"main","last_synced_at":"2025-04-11T00:43:37.702Z","etag":null,"topics":["expo","react","react-native","tabs","tabview"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/PedroBern.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-11-19T11:49:34.000Z","updated_at":"2025-04-09T23:49:21.000Z","dependencies_parsed_at":"2023-12-25T01:09:10.077Z","dependency_job_id":"b80b72b1-209e-4ab2-9514-183b8dcd1c96","html_url":"https://github.com/PedroBern/react-native-collapsible-tab-view","commit_stats":{"total_commits":432,"total_committers":14,"mean_commits":"30.857142857142858","dds":0.5486111111111112,"last_synced_commit":"b5f77dd4dc8681e23e431bf3b8e64c65a608cbc2"},"previous_names":[],"tags_count":86,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PedroBern%2Freact-native-collapsible-tab-view","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PedroBern%2Freact-native-collapsible-tab-view/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PedroBern%2Freact-native-collapsible-tab-view/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PedroBern%2Freact-native-collapsible-tab-view/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/PedroBern","download_url":"https://codeload.github.com/PedroBern/react-native-collapsible-tab-view/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248724586,"owners_count":21151559,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["expo","react","react-native","tabs","tabview"],"created_at":"2024-10-14T04:43:17.400Z","updated_at":"2025-04-13T13:52:50.779Z","avatar_url":"https://github.com/PedroBern.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# React Native Collapsible Tab View\n\n[![Build Status][build-badge]][build]\n[![Version][version-badge]][package]\n[![MIT License][license-badge]][license]\n[![Runs with Expo][expo-badge]][expo]\n\n- [Expo App](#expo-app)\n- [Demo](#demo)\n- [Features](#features)\n- [Installation](#installation)\n- [Quick Start](#quick-start)\n- [Guides](#guides)\n  - [Scroll on Header](#scroll-on-header)\n- [API Reference](#api-reference)\n  - [Core](#core)\n    - [Tabs.Container](#tabscontainer)\n    - [Tabs.Lazy](#tabslazy)\n    - [Tabs.FlatList](#tabsflatlist)\n    - [Tabs.FlashList](#tabsflatlist)\n    - [Tabs.MasonryFlashList](#tabsmasonryflatlist)\n    - [Tabs.SectionList](#tabssectionlist)\n    - [Tabs.ScrollView](#tabsscrollview)\n    - [Ref](#ref)\n  - [Hooks](#hooks)\n    - [useCollapsibleStyle](#usecollapsiblestyle)\n    - [useAnimatedTabIndex](#useanimatedtabindex)\n    - [useFocusedTab](#usefocusedtab)\n    - [useHeaderMeasurements](#useheadermeasurements)\n  - [Default Tab Bar](#default-tab-bar)\n    - [MaterialTabBar](#materialtabbar)\n    - [MaterialTabItem](#materialtabitem)\n- [Known Issues](#known-issues)\n  - [Android FlatList Pull to Refresh](#android-flatlist-pull-to-refresh)\n  - [iOS FlatList StickyHeaderIndices](#ios-flatlist-stickyheaderindices)\n  - [ref.setIndex](#refsetindex)\n- [Alternative Libraries](#alternative-libraries)\n- [Contributing](#contributing)\n  - [Documentation Changes](#documentation-changes)\n\n## 🚀 Version 6 released with Reanimated v3 support\n\nReact Native Collapsible Tab View is a versatile library for creating collapsible tab views using [Reanimated](https://github.com/software-mansion/react-native-reanimated).\n\n- Explore the [examples](https://github.com/PedroBern/react-native-collapsible-tab-view/tree/main/example) for the source code of the Expo app.\n\n**Credits**\n\nThe [react-native-tab-view](https://github.com/satya164/react-native-tab-view) example app was used as a template for the demos.\n\n# Demo\n\n|                                                     Default                                                      |                                                     Snap                                                      |                                                revealHeaderOnScroll                                                |                                               revealHeaderOnScroll + Snap                                               |\n| :--------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------: |\n| \u003cimg src=\"https://github.com/PedroBern/react-native-collapsible-tab-view/raw/main/demo/default.gif\" width=\"360\"\u003e | \u003cimg src=\"https://github.com/PedroBern/react-native-collapsible-tab-view/raw/main/demo/snap.gif\" width=\"360\"\u003e | \u003cimg src=\"https://github.com/PedroBern/react-native-collapsible-tab-view/raw/main/demo/diffClamp.gif\" width=\"360\"\u003e | \u003cimg src=\"https://github.com/PedroBern/react-native-collapsible-tab-view/raw/main/demo/diffClamp_snap.gif\" width=\"360\"\u003e |\n\n# Features\n\n- UI thread animations and interactions\n- High customizability\n- Full [TypeScript](https://typescriptlang.org) support\n- Lazy loading with fade-in animation\n- DiffClamp header\n- Interpolated header\n- Scroll snap (with interpolated header)\n- Animated snap (with diffClamp header)\n- Scrollable tabs, inspired by the [react-native-tab-view](https://github.com/satya164/react-native-tab-view) tab bar\n\n# Installation\n\nTo install the library, open a terminal in your project's root directory and run:\n\n```sh\nyarn add react-native-collapsible-tab-view react-native-pager-view\n```\n\nThen, add [Reanimated](https://docs.swmansion.com/react-native-reanimated), [follow the official installation guide](https://docs.swmansion.com/react-native-reanimated/docs/fundamentals/installation).\n\n# Quick Start\n\n```tsx\nimport React from 'react'\nimport { View, StyleSheet, ListRenderItem } from 'react-native'\nimport { Tabs } from 'react-native-collapsible-tab-view'\n\nconst HEADER_HEIGHT = 250\n\nconst DATA = [0, 1, 2, 3, 4]\nconst identity = (v: unknown): string =\u003e v + ''\n\nconst Header = () =\u003e {\n  return \u003cView style={styles.header} /\u003e\n}\n\nconst Example: React.FC = () =\u003e {\n  const renderItem: ListRenderItem\u003cnumber\u003e = React.useCallback(({ index }) =\u003e {\n    return (\n      \u003cView style={[styles.box, index % 2 === 0 ? styles.boxB : styles.boxA]} /\u003e\n    )\n  }, [])\n\n  return (\n    \u003cTabs.Container\n      renderHeader={Header}\n      headerHeight={HEADER_HEIGHT} // optional\n    \u003e\n      \u003cTabs.Tab name=\"A\"\u003e\n        \u003cTabs.FlatList\n          data={DATA}\n          renderItem={renderItem}\n          keyExtractor={identity}\n        /\u003e\n      \u003c/Tabs.Tab\u003e\n      \u003cTabs.Tab name=\"B\"\u003e\n        \u003cTabs.ScrollView\u003e\n          \u003cView style={[styles.box, styles.boxA]} /\u003e\n          \u003cView style={[styles.box, styles.boxB]} /\u003e\n        \u003c/Tabs.ScrollView\u003e\n      \u003c/Tabs.Tab\u003e\n    \u003c/Tabs.Container\u003e\n  )\n}\n\nconst styles = StyleSheet.create({\n  box: {\n    height: 250,\n    width: '100%',\n  },\n  boxA: {\n    backgroundColor: 'white',\n  },\n  boxB: {\n    backgroundColor: '#D8D8D8',\n  },\n  header: {\n    height: HEADER_HEIGHT,\n    width: '100%',\n    backgroundColor: '#2196f3',\n  },\n})\n\nexport default Example\n\n```\n\n# Guides\n\n## Scrolling on the Header\n\nTo enable scrolling from the header, follow these steps:\n\n- If the `HeaderComponent` **does not** contain touchable components, set the `pointerEvents` prop to `'none'`.\n- If the `HeaderComponent` **does** contain touchable components, set the `pointerEvents` prop to `'box-none'` to ensure they function properly.\n\nNote: If any child component within the `HeaderComponent` should **not** respond to touches, such as an `\u003cImage /\u003e` element, set its `pointerEvents` prop to `'none'`. Otherwise, it may unintentionally become the target of a touch gesture on iOS devices and prevent scrolling.\n\n# API Reference\n\n## Core\n\n### Tabs.Container\n\nBasic usage looks like this:\n\n```tsx\nimport { Tabs } from 'react-native-collapsible-tab-view'\n\nconst Example = () =\u003e {\n   return (\n     \u003cTabs.Container renderHeader={MyHeader}\u003e\n       \u003cTabs.Tab name=\"A\"\u003e\n         \u003cScreenA /\u003e\n       \u003c/Tabs.Tab\u003e\n       \u003cTabs.Tab name=\"B\"\u003e\n         \u003cScreenB /\u003e\n       \u003c/Tabs.Tab\u003e\n     \u003c/Tabs.Container\u003e\n   )\n}\n```\n\n#### Props\n\n|name|type|default|description|\n|:----:|:----:|:----:|:----:|\n|`allowHeaderOverscroll`|`boolean \\| undefined`|`false`|Whether the header moves down during overscrolling (for example on pull-to-refresh on iOS) or sticks to the top|\n|`cancelLazyFadeIn`|`boolean \\| undefined`|||\n|`cancelTranslation`|`boolean \\| undefined`|||\n|`containerStyle`|`StyleProp\u003cViewStyle\u003e`|||\n|`headerContainerStyle`|`StyleProp\u003cAnimateStyle\u003cViewStyle\u003e\u003e`|||\n|`headerHeight`|`number \\| undefined`||Is optional, but will optimize the first render.|\n|`initialTabName`|`string \\| undefined`|||\n|`lazy`|`boolean \\| undefined`||If lazy, will mount the screens only when the tab is visited. There is a default fade in transition.|\n|`minHeaderHeight`|`number \\| undefined`||Header minimum height when collapsed|\n|`onIndexChange`|`((index: number) =\u003e void) \\| undefined`||Callback fired when the index changes. It receives the current index.|\n|`onTabChange`|`(data: { prevIndex: number index: number prevTabName: T tabName: T }) =\u003e void`||Callback fired when the tab changes. It receives the previous and current index and tabnames.|\n|`pagerProps`|`Omit\u003cFlatListProps\u003cnumber\u003e, 'data' \\| 'keyExtractor' \\| 'renderItem' \\| 'horizontal' \\| 'pagingEnabled' \\| 'onScroll' \\| 'showsHorizontalScrollIndicator' \\| 'getItemLayout'\u003e`||Props passed to the pager. If you want for example to disable swiping, you can pass `{ scrollEnabled: false }`|\n|`renderHeader`|`(props: TabBarProps\u003cTabName\u003e) =\u003e React.ReactElement \\| null`|||\n|`renderTabBar`|`(props: TabBarProps\u003cTabName\u003e) =\u003e React.ReactElement \\| null`|`(props: TabBarProps\u003cTabName\u003e) =\u003e MaterialTabBar`||\n|`revealHeaderOnScroll`|`boolean \\| undefined`||Reveal header when scrolling down. Implements diffClamp.|\n|`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.|\n|`tabBarHeight`|`number \\| undefined`||Is optional, but will optimize the first render.|\n|`width`|`number \\| undefined`||Custom width of the container. Defaults to the window width.|\n\n### Tabs.Tab\n\nWrap your screens with `Tabs.Tab`. Basic usage looks like this:\n\n```tsx\n\u003cTabs.Container ...\u003e\n  \u003cTabs.Tab name=\"A\" label=\"First Tab\"\u003e\n   \u003cScreenA /\u003e\n  \u003c/Tabs.Tab\u003e\n  \u003cTabs.Tab name=\"B\"\u003e\n   \u003cScreenA /\u003e\n  \u003c/Tabs.Tab\u003e\n\u003c/Tabs.Container\u003e\n```\n\n#### Props\n\n|name|type|\n|:----:|:----:|\n|`label`|`string \\| ((props: TabItemProps\u003cT\u003e) =\u003e ReactNode) \\| undefined`|\n|`name`|`T`|\n\n### Tabs.Lazy\n\nTypically used internally, but if you want to mix lazy and regular screens you can wrap the lazy ones with this component.\n\n#### Props\n\n|name|type|\n|:----:|:----:|\n|`cancelLazyFadeIn`|`boolean \\| undefined`|\n|`startMounted`|`boolean \\| undefined`|\n\n### Tabs.FlatList\n\nUse like a regular FlatList.\n\n### Tabs.FlashList\n\nUse like a regular FlashList.\n\n### Tabs.MasonryFlashList\n\nUse like a regular MasonryFlashList.\n\n### Tabs.ScrollView\n\nUse like a regular ScrollView.\n\n### Tabs.SectionList\n\nUse like a regular SectionList.\n\n\n\n### Ref\n\nYou can pass a ref to `Tabs.Container`.\n\n```tsx\nconst ref = React.useRef()\n\u003cTabs.Container ref={ref}\u003e\n```\n\n|     method      |             type             |\n| :-------------: | :--------------------------: |\n|    jumpToTab    |    `(name: T) =\u003e boolean`    |\n|    setIndex     | `(index: number) =\u003e boolean` |\n|  getFocusedTab  |          `() =\u003e T`           |\n| getCurrentIndex |        `() =\u003e number`        |\n\n## Hooks\n\n### `useCollapsibleStyle`\n\nThis 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.\n\n```tsx\nconst {\n  contentContainerStyle,\n  progressViewOffset,\n  style,\n} = useCollapsibleStyle()\n```\n\n#### Values\n\n|         name          |                     type                     |\n| :-------------------: | :------------------------------------------: |\n| contentContainerStyle | `{ minHeight: number; paddingTop: number; }` |\n|  progressViewOffset   |                   `number`                   |\n|         style         |             `{ width: number; }`             |\n\n### `useAnimatedTabIndex`\n\nThis 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.\n\n```tsx\nconst tabIndex = useAnimatedTabIndex()\n```\n\n### `useFocusedTab`\n\nThis hook returns the name of the currently focused tab.\n\n```tsx\nconst focusedTab = useFocusedTab()\n```\n\n### `useHeaderMeasurements`\n\nThis 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.\n\n```tsx\nconst { top, height } = useHeaderMeasurements()\n```\n\n### useCurrentTabScrollY\n\nThis hook returns the vertical scroll position of the current tab as an Animated SharedValue. \n\nSince 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.\n\n\n```tsx\nconst scrollY = useCurrentTabScrollY()\n```\n\n\n## Default Tab Bar\n\n### MaterialTabItem\n\nAny additional props are passed to the pressable component.\n\n#### Props\n\n|name|type|description|\n|:----:|:----:|:----:|\n|`activeColor`|`string \\| undefined`|Color applied to the label when active|\n|`inactiveColor`|`string \\| undefined`|Color applied to the label when inactive|\n|`inactiveOpacity`|`number \\| undefined`||\n|`index`|`number`||\n|`indexDecimal`|`SharedValue\u003cnumber\u003e`||\n|`label`|`string \\| ((props: TabItemProps\u003cT\u003e) =\u003e ReactNode)`||\n|`labelStyle`|`StyleProp\u003cAnimateStyle\u003cTextStyle\u003e\u003e`|Style to apply to the tab item label|\n|`name`|`T`||\n|`onLayout`|`(((event: LayoutChangeEvent) =\u003e void) \u0026 ((event: LayoutChangeEvent) =\u003e void)) \\| undefined`|Invoked on mount and layout changes with {nativeEvent: { layout: {x, y, width, height}}}.|\n|`onPress`|`(name: T) =\u003e void`||\n|`pressColor`|`string \\| undefined`||\n|`pressOpacity`|`number \\| undefined`||\n|`scrollEnabled`|`boolean \\| undefined`||\n|`style`|`StyleProp\u003cViewStyle\u003e`|Either view styles or a function that receives a boolean reflecting whether the component is currently pressed and returns view styles.|\n\n\n\n# Known Issues\n\n## Android FlatList Pull to Refresh\n\nRefer to [this open issue](https://github.com/software-mansion/react-native-reanimated/issues/1703). We utilize [scrollTo](https://docs.swmansion.com/react-native-reanimated/docs/next/api/nativeMethods/scrollTo) to synchronize the unfocused tabs. While it is intended for use with `ScrollView`, it works well with `FlatList`, until the `RefreshControl` is added. Note that this issue occurs only on Android.\n\n**Workaround**: Check out the `Android Shared Pull To Refresh` example in the expo app. You can implement a single pull-to-refresh for the `Tabs.Container`.\n\n## iOS FlatList StickyHeaderIndices and iOS SectionList StickySectionHeadersEnabled\n\nWhen using the `stickyHeaderIndices` prop on a FlatList or `stickySectionHeadersEnabled` on a SectionList, the sticky elements do not scroll up as the header collapses. This issue is specific to iOS.\n\nSee [#136](https://github.com/PedroBern/react-native-collapsible-tab-view/issues/136).\n\n## `ref.setIndex`\n\nThis is not an issue per se, but it's essential to be aware of it. When using `containerRef.current.setIndex(i)`, if you set it to the current index, the screen will scroll to the top. You can prevent this behavior as follows:\n\n\n```ts\nconst index = pageRef.current?.getCurrentIndex()\nif (index !== nextIndex) {\n  pageRef.current?.setIndex(nextIndex)\n}\n```\n\n# Alternative Libraries\n\nIf you do not require a full-featured tab view, consider another option: a simple segmented control / material tab bar without swiping or snapping, using only the React Native Animated API.\n\n- [react-native-collapsible-segmented-view](https://github.com/PedroBern/react-native-collapsible-segmented-view)\n\n# Contributing and running the Example\n\nWhile developing, you can run the [example app](/example/README.md) to test your changes.\n\nFirst run `yarn` in root:\n```sh\nyarn\n```\n\nThen prepare the example:\n```sh\ncd example\nyarn\n```\n\nThen run the example:\n```\nyarn ios\n```\n\nPlease follow the [angular commit message format](https://github.com/angular/angular/blob/master/CONTRIBUTING.md#-commit-message-format).\n\nMake sure your code passes TypeScript and ESLint. Run the following to verify:\n\n```sh\nyarn typescript\nyarn lint\n```\n\nTo fix formatting errors, run the following:\n\n```sh\nyarn lint -- --fix\n```\n\n## Documentation changes\n\nEdit the [README_TEMPLATE](https://github.com/PedroBern/react-native-collapsible-tab-view/tree/main/documentation/README_TEMPLATE.md), or update the docstrings inside the `src` folder, and run:\n\n```sh\nyarn docs\n```\n\n\u003c!-- badges --\u003e\n\n[build-badge]: https://img.shields.io/circleci/build/github/PedroBern/react-native-collapsible-tab-view/main.svg?style=flat-square\n[build]: https://app.circleci.com/pipelines/github/PedroBern/react-native-collapsible-tab-view\n[version-badge]: https://img.shields.io/npm/v/react-native-collapsible-tab-view.svg?style=flat-square\n[package]: https://www.npmjs.com/package/react-native-collapsible-tab-view\n[license-badge]: https://img.shields.io/npm/l/react-native-collapsible-tab-view.svg?style=flat-square\n[license]: https://opensource.org/licenses/MIT\n[expo-badge]: https://img.shields.io/badge/Runs%20with%20Expo-4630EB.svg?style=flat-square\u0026logo=EXPO\u0026labelColor=f3f3f3\u0026logoColor=000\n[expo]: https://github.com/expo/expo\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpedrobern%2Freact-native-collapsible-tab-view","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpedrobern%2Freact-native-collapsible-tab-view","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpedrobern%2Freact-native-collapsible-tab-view/lists"}