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

react-native-profile-sticky-tab

v1.1.4

Published

A React Native library for creating sticky headers and collapsible profile sections with synchronized scroll across FlatList, FlashList, and ScrollView. Built with Reanimated.

Downloads

1,311

Readme

react-native-profile-sticky-tab

A tab component with a fixed header and collapsible profile area for React Native.

This library combines react-native-tab-view, react-native-reanimated, and animated lists to deliver a common profile-screen experience: a fixed header at the top, a profile information area that collapses on scroll, and tabs with synchronized scroll position between FlatList, FlashList, and ScrollView.

| Example | Instagram Example | | :---------------------: | :-------------------------------: | | | |

Features

  • Fixed header at the top of the screen.
  • Collapsible profile area below the header.
  • Tab bar integrated with react-native-tab-view.
  • Scroll synchronization between tabs.
  • Support for FlatList, FlashList, and ScrollView.
  • Programmatic control through useStickyTab.
  • UI-thread animated scrolling with Reanimated.
  • Composable API for custom tab bars.

Installation

npm install react-native-profile-sticky-tab

Also install the peer dependencies:

npm install react-native-reanimated react-native-tab-view @shopify/flash-list

If your project does not use Reanimated yet, make sure to complete the setup required by react-native-reanimated in your app, including the Babel plugin when necessary.

Basic Usage

import ProfileStickyTab from "react-native-profile-sticky-tab";
import { Text, View } from "react-native";
import { TabBar } from "react-native-tab-view";

const DATA = Array.from({ length: 40 }, (_, index) => ({
  id: String(index),
  title: `Post ${index + 1}`,
}));

export function ProfileScreen() {
  return (
    <ProfileStickyTab.Provider>
      <ProfileStickyTab
        header={<View style={{ height: 72, backgroundColor: "#111827" }} />}
        renderTabBar={(props) => <TabBar {...props} />}
        tabKeyScenes={[
          {
            key: "posts",
            title: "Posts",
            renderComponent: (stickyTab) => (
              <ProfileStickyTab.FlatList
                stickyTab={stickyTab}
                data={DATA}
                keyExtractor={(item) => item.id}
                renderItem={({ item }) => (
                  <Text style={{ padding: 16 }}>{item.title}</Text>
                )}
              />
            ),
          },
          {
            key: "about",
            title: "About",
            renderComponent: (stickyTab) => (
              <ProfileStickyTab.ScrollView stickyTab={stickyTab}>
                <Text style={{ padding: 16 }}>
                  About tab content
                </Text>
              </ProfileStickyTab.ScrollView>
            ),
          },
        ]}
      >
        <View style={{ height: 220, backgroundColor: "#2563eb" }}>
          <Text style={{ color: "white", padding: 16, fontSize: 24 }}>
            Rui Lucas
          </Text>
          <Text style={{ color: "white", paddingHorizontal: 16 }}>
            React Native Developer
          </Text>
        </View>
      </ProfileStickyTab>
    </ProfileStickyTab.Provider>
  );
}

How the Structure Works

<ProfileStickyTab.Provider>
  <ProfileStickyTab
    header={<Header />}
    renderTabBar={(props) => <TabBar {...props} />}
    tabKeyScenes={scenes}
  >
    <ProfileInfo />
  </ProfileStickyTab>
</ProfileStickyTab.Provider>

ProfileStickyTab.Provider stores the shared scroll state, active tab state, and layout heights.

header stays fixed at the top of the screen.

children represents the collapsible area, usually used for the profile photo, bio, stats, or profile actions.

tabKeyScenes defines the tabs and the component rendered for each one.

Each scene must render one of the library containers and pass the stickyTab object received in renderComponent.

Tab Containers

FlatList

Use it when the tab renders a standard React Native list.

<ProfileStickyTab.FlatList
  stickyTab={stickyTab}
  data={items}
  keyExtractor={(item) => item.id}
  renderItem={({ item }) => <Item item={item} />}
/>

FlashList

Use it when the tab renders large lists and you want to use @shopify/flash-list.

<ProfileStickyTab.FlashList
  stickyTab={stickyTab}
  data={items}
  keyExtractor={(item) => item.id}
  renderItem={({ item }) => <Item item={item} />}
  estimatedItemSize={80}
/>

ScrollView

Use it when the tab has free-form, smaller, or more static content.

<ProfileStickyTab.ScrollView stickyTab={stickyTab}>
  <ProfileDetails />
</ProfileStickyTab.ScrollView>

Programmatic Control

Use useStickyTab in any component rendered inside ProfileStickyTab.Provider.

import { useStickyTab } from "react-native-profile-sticky-tab";
import { Pressable, Text, View } from "react-native";

export function CustomActions() {
  const {
    currentTab,
    setTab,
    scrollToY,
    collapseHeader,
    expandHeader,
  } = useStickyTab();

  return (
    <View style={{ flexDirection: "row", gap: 12 }}>
      <Pressable onPress={() => setTab(0)}>
        <Text style={{ fontWeight: currentTab === 0 ? "700" : "400" }}>
          Posts
        </Text>
      </Pressable>

      <Pressable onPress={() => setTab(1)}>
        <Text style={{ fontWeight: currentTab === 1 ? "700" : "400" }}>
          About
        </Text>
      </Pressable>

      <Pressable onPress={() => collapseHeader(true)}>
        <Text>Collapse header</Text>
      </Pressable>

      <Pressable onPress={() => expandHeader(true)}>
        <Text>Expand header</Text>
      </Pressable>

      <Pressable onPress={() => scrollToY(300, true)}>
        <Text>Scroll to Y 300</Text>
      </Pressable>
    </View>
  );
}

You can also access the hook through the component namespace:

const stickyTab = ProfileStickyTab.useStickyTab();

Hook API

| Return | Type | Description | | ---------------- | ----------------------------------------- | ----------------------------------------------------- | | currentTab | number | Index of the active tab in React state. | | setTab | (index: number) => void | Changes the active tab programmatically. | | scrollToY | (y: number, animated?: boolean) => void | Scrolls the active tab to a vertical position. | | collapseHeader | (animated?: boolean) => void | Scrolls to the limit that collapses the profile area. | | expandHeader | (animated?: boolean) => void | Scrolls back to the top and expands the profile area. |

Props

ProfileStickyTab

| Prop | Type | Description | | -------------- | ---------------------- | ---------------------------------------------------------- | | header | ReactNode | Fixed content at the top of the screen. | | children | ReactNode | Collapsible content below the header. | | renderTabBar | (props) => ReactNode | Function that renders the react-native-tab-view tab bar. | | tabKeyScenes | TabScene[] | List of tabs and their respective components. |

TabScene

type TabScene = {
  key: string;
  title: string;
  renderComponent: (stickyTab: StickyTabType) => ReactNode;
  icon?: (color: string) => ReactNode;
};

type StickyTabType = {
  key: string;
  index: number;
};

Containers

All containers receive the required stickyTab prop.

| Component | Additional props | | ----------------------------- | ------------------------------------------- | | ProfileStickyTab.FlatList | Animated.FlatList props. | | ProfileStickyTab.FlashList | @shopify/flash-list props. | | ProfileStickyTab.ScrollView | Animated.ScrollView props and children. |

Exports

import ProfileStickyTab, {
  ProfileStickyTab as NamedProfileStickyTab,
  useStickyTab,
} from "react-native-profile-sticky-tab";

import type {
  ProfileStickyTabProps,
  ProfileStickyTabFlatListProps,
  ProfileStickyTabFlashListProps,
  ProfileStickyTabScrollViewProps,
} from "react-native-profile-sticky-tab";

Best Practices

  • Wrap the screen with ProfileStickyTab.Provider.
  • Use ProfileStickyTab.FlatList, ProfileStickyTab.FlashList, or ProfileStickyTab.ScrollView inside each renderComponent.
  • Always pass the stickyTab object received by the scene to the tab container.
  • Use FlashList for large lists and provide estimatedItemSize.
  • Use useStickyTab only inside the provider.
  • Avoid manually controlling the list scroll from outside if your goal is to keep it synchronized with the collapsible header.

License

MIT