npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@orionarm/react-native-collapse-tabs

v1.1.6

Published

A high-performance React Native collapsible tabs component with sticky/animated header, swipeable pages, and per-tab scroll. Built on react-native-pager-view and react-native-reanimated v3.

Readme

@orionarm/react-native-collapse-tabs

npm version npm downloads license platforms types

A high-performance React Native collapsible tabs component with sticky / animated header, swipeable pages, and per-tab scroll state. Built on react-native-pager-view and react-native-reanimated.

Preview


Features

  • 📜 Collapsible header — the header smoothly collapses while the inner list is scrolled.
  • 🗂 Swipeable tabs — horizontal paging powered by react-native-pager-view.
  • 🎚 Per-tab scroll state — each tab keeps its own scroll position.
  • 🪄 Animated tab switching — header smoothly tweens between tabs (no sudden jumps).
  • 🛡 Overscroll-safe — pull-to-refresh / bounce area won't push the header off screen.
  • 🎨 Custom header & tab bar — bring your own UI, or use the built-in DefaultTabBar.
  • 🪝 onScroll passthrough — wrapped lists still forward your own scroll handler (worklet or JS).
  • Reanimated 3 worklets — animations run on the UI thread for 60fps.
  • 🧩 Drop-in scrollables — wrapped FlatList / ScrollView / SectionList handle the plumbing for you.
  • 📐 Dynamic header height — omit headerHeight and the header is auto-measured via onLayout.

When to use

Use @orionarm/react-native-collapse-tabs when you need a Twitter / Instagram / YouTube profile style screen in React Native — a large header that collapses as you scroll, sticky tabs underneath, swipeable pages, and per-tab scroll memory.

Typical use cases:

  • User / profile screens with a hero header and Posts / Likes / Media tabs
  • Product detail pages with tabbed sections (Description / Reviews / Q&A)
  • Restaurant / store pages with collapsing cover image and category tabs
  • Music / video apps with an artist header and Songs / Albums / Playlists tabs
  • Any screen that needs a collapsing header + sticky tab bar + horizontal swipe

Comparison with similar libraries

| Library | Collapsible header | Swipeable tabs | Per-tab scroll | Reanimated v3 worklets | Bundle size | | --------------------------------------------- | ------------------ | -------------- | -------------- | ---------------------- | ----------- | | @orionarm/react-native-collapse-tabs | ✅ | ✅ | ✅ | ✅ | ~30 KB | | react-native-collapsible-tab-view | ✅ | ✅ | ✅ | ✅ | larger | | react-native-scrollable-tab-view (legacy) | partial | ✅ | ❌ | ❌ | small | | react-native-tab-view | ❌ | ✅ | ❌ | partial | medium | | react-native-sticky-parallax-header | ✅ | ❌ | ❌ | partial | medium |

Compared to react-native-collapsible-tab-view, this library aims for a smaller API surface and uses react-native-pager-view directly for native paging — fewer abstractions, easier to drop in, and easier to customize.


Requirements

| Peer dependency | Version | | ------------------------------ | ---------- | | react | >=16.8.0 | | react-native | >=0.60.0 | | react-native-gesture-handler | >=2.0.0 | | react-native-pager-view | >=6.0.0 | | react-native-reanimated | >=3.0.0 |

Make sure Reanimated is set up correctly (Babel plugin + react-native-reanimated/plugin at the end of your babel.config.js plugins array).


Installation

# npm
npm install @orionarm/react-native-collapse-tabs

# yarn
yarn add @orionarm/react-native-collapse-tabs

# pnpm
pnpm add @orionarm/react-native-collapse-tabs

Then install the peer dependencies if you haven't already:

npm install react-native-pager-view react-native-reanimated react-native-gesture-handler

For iOS, don't forget to install pods:

cd ios && pod install

Quick Start

import React from "react";
import { Text, View, StyleSheet } from "react-native";
import {
  CollapseTabs,
  Tab,
  FlatList,
} from "@orionarm/react-native-collapse-tabs";

const HEADER_HEIGHT = 200;
const TAB_BAR_HEIGHT = 44;

export default function Example() {
  return (
    <CollapseTabs
      headerHeight={HEADER_HEIGHT}
      tabBarHeight={TAB_BAR_HEIGHT}
      renderHeader={() => (
        <View style={styles.header}>
          <Text style={styles.headerText}>My Profile</Text>
        </View>
      )}
    >
      <Tab name="Posts">
        <FlatList
          name="Posts"
          data={Array.from({ length: 30 }).map((_, i) => `Post ${i}`)}
          keyExtractor={(item) => item}
          renderItem={({ item }) => (
            <View style={styles.row}>
              <Text>{item}</Text>
            </View>
          )}
        />
      </Tab>

      <Tab name="Likes">
        <FlatList
          name="Likes"
          data={Array.from({ length: 30 }).map((_, i) => `Like ${i}`)}
          keyExtractor={(item) => item}
          renderItem={({ item }) => (
            <View style={styles.row}>
              <Text>{item}</Text>
            </View>
          )}
        />
      </Tab>
    </CollapseTabs>
  );
}

const styles = StyleSheet.create({
  header: {
    flex: 1,
    backgroundColor: "#2D8CFF",
    justifyContent: "center",
    alignItems: "center",
  },
  headerText: { color: "#fff", fontSize: 22, fontWeight: "600" },
  row: {
    padding: 16,
    borderBottomWidth: StyleSheet.hairlineWidth,
    borderColor: "#eee",
  },
});

⚠️ Important: the name prop of <Tab> and the name prop of the wrapped <FlatList> / <ScrollView> / <SectionList> must match — that's how each tab's scroll position is tracked.


API

<CollapseTabs />

The root container.

| Prop | Type | Required | Description | | ---------------------- | ------------------------------------------------------- | -------- | ------------------------------------------------------------------------------------------------------- | | headerHeight | number | | Header height. If omitted, it's auto-measured via onLayout. Pass explicitly for a stable first paint. | | tabBarHeight | number | ✅ | Fixed height of the tab bar. | | children | TabReactElement \| TabReactElement[] | ✅ | One or more <Tab> children. | | initialTabName | string | | Tab to focus on mount. Defaults to the first child. | | minHeaderHeight | number | | Minimum visible header height once collapsed. Default 0. | | renderHeader | (props: HeaderProps) => ReactElement \| null | | Render function for the header content. | | renderTabBar | (props: TabBarProps) => ReactElement \| null | | Render function for a custom tab bar. Falls back to <DefaultTabBar> if not provided. | | containerStyle | StyleProp<ViewStyle> | | Style for the outer container. | | headerContainerStyle | StyleProp<ViewStyle> | | Style for the absolutely-positioned header wrapper. | | pagerProps | Omit<PagerViewProps, "onPageScroll" \| "initialPage"> | | Extra props forwarded to PagerView. | | onIndexChange | (index: number) => void | | Fired after the focused tab changes. |

<Tab />

Wraps a single tab's content. Should be a direct child of <CollapseTabs>.

| Prop | Type | Required | Description | | ---------- | ----------------- | -------- | --------------------------------------------------------------------------------- | | name | string | ✅ | Unique identifier — must match the inner list's name. | | label | string | | Optional display label (currently used by DefaultTabBar via name). | | children | React.ReactNode | ✅ | Tab content — usually a wrapped <FlatList>, <ScrollView>, or <SectionList>. |

<FlatList />, <ScrollView /> and <SectionList />

Drop-in replacements for the standard components, pre-wired to the collapse-tabs scroll system.

| Prop | Type | Required | Description | | ---------- | --------------------------------------- | -------- | ----------------------------------------------------------------------------------- | | name | string | ✅ | Must match the parent <Tab name="..." />. | | onScroll | (event) => void or Reanimated worklet | | Forwarded after the internal handler runs. Works with both JS and worklet handlers. | | ... | — | | All other standard FlatList / ScrollView / SectionList props. |

They automatically apply paddingTop: headerHeight + tabBarHeight to the content so your first item starts below the header.

// Custom onScroll still works — gets called after the header math runs.
<FlatList
  name="Posts"
  data={data}
  renderItem={renderItem}
  onScroll={(e) => {
    console.log("user scroll y =", e.nativeEvent.contentOffset.y);
  }}
/>

<DefaultTabBar />

A minimal built-in tab bar with a sliding underline indicator. Pass any custom UI through renderTabBar if you need something different.

useTabsContext()

Hook for advanced use cases (e.g. building a fully custom header/tab bar that needs access to the shared scroll state).

const {
  headerHeight,
  tabBarHeight,
  headerScrollDistance,
  tabNames,
  index, // SharedValue<number>
  indexDecimal, // SharedValue<number>
  focusedTab, // SharedValue<string>
  scrollY, // SharedValue<Record<string, number>>
  headerTranslateY, // SharedValue<number>
  containerRef,
} = useTabsContext();

Customization

Custom tab bar

<CollapseTabs
  headerHeight={200}
  tabBarHeight={44}
  renderTabBar={({ tabNames, indexDecimal, onTabPress }) => (
    <MyFancyTabBar
      tabs={tabNames}
      indexDecimal={indexDecimal}
      onPress={onTabPress}
    />
  )}
>
  {/* ... */}
</CollapseTabs>

Animated header

renderHeader receives the same HeaderProps so you can animate things based on indexDecimal or read headerTranslateY from useTabsContext() inside a child component.


Types

All public types are exported from the package root:

import type {
  CollapseTabsProps,
  TabProps,
  TabBarProps,
  HeaderProps,
  TabName,
} from "@orionarm/react-native-collapse-tabs";

FAQ

How is this different from react-native-collapsible-tab-view?

Both solve the same problem. @orionarm/react-native-collapse-tabs has a smaller surface area, uses react-native-pager-view directly (instead of react-native-tab-view), and exposes the underlying Reanimated SharedValues through useTabsContext() so you can build fully custom headers/tab bars without forking.

Does it work with Expo?

Yes. It works with Expo SDK 49+ (any version that supports react-native-reanimated v3 and react-native-pager-view 6+). Run npx expo install react-native-reanimated react-native-pager-view react-native-gesture-handler and you're set.

Does it support iOS and Android?

Yes — both platforms are first-class. All animations run on the UI thread via Reanimated worklets, so performance is identical on both.

Does it support pull-to-refresh?

Yes. Pass refreshControl to the wrapped <FlatList> just like a normal RN list. The library handles overscroll so the header won't fly off-screen during the pull gesture.

Can I use a custom tab bar / animated header?

Absolutely. Pass renderTabBar and renderHeader props, or read the shared scroll state via useTabsContext() to drive your own animations.

Does it support dynamic header height?

Yes. headerHeight is optional — when omitted, the header is measured via onLayout and the layout updates automatically. Pass headerHeight explicitly when you need a stable first paint (otherwise list content briefly mounts with paddingTop: tabBarHeight before the first layout pass).

<CollapseTabs tabBarHeight={44} renderHeader={() => <MyDynamicHeader />}>
  {/* ... */}
</CollapseTabs>

How do I keep each tab's scroll position independent?

It's automatic. Just make sure the name prop on <Tab> matches the name prop on the inner <FlatList> / <ScrollView> / <SectionList>.

Does it support SectionList?

Yes. Import the wrapped SectionList from the package and use it the same way as a normal RN SectionList.

Why Reanimated v3?

Reanimated v3 worklets let scroll-driven animations run entirely on the UI thread, which is required for jank-free 60fps header collapse on lower-end Android devices.


Keywords

react-native collapsible tabs · react-native sticky header tabs · react-native parallax header · react-native tab view with collapsing header · react-native scrollable tab bar · react-native pager view tabs · react-native animated tabs · react-native profile screen · instagram profile tabs react-native · twitter profile header react-native


Roadmap

  • [x] Dynamic header height
  • [x] SectionList support
  • [ ] Horizontal-list support
  • [ ] Snap-to-collapse behavior
  • [ ] Example app

License

ISC © yanan_orionarm